2012-08-13 29 views
52

Voglio ridimensionare l'immagine scattata dalla fotocamera iOS sul lato client con HTML5 Canvas ma continuo a correre in questo strano bug in cui l'immagine ha un rapporto errato se maggiore di ~ 1.5mbHTML5 Canvas drawImage ratio bug iOS

Funziona sul desktop ma non nell'ultima versione di iOS con l'API di caricamento multimediale.

È possibile vedere un esempio qui: http://jsbin.com/ekuros/1

Qualsiasi idea di come risolvere questo problema per favore? È un problema di memoria?

$('#file').on('change', function (e) { 
    var file = e.currentTarget.files[0]; 
    var reader = new FileReader(); 
    reader.onload = function (e) { 
     var image = $('<img/>'); 
     image.on('load', function() { 
      var square = 320; 
      var canvas = document.createElement('canvas'); 

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

      var context = canvas.getContext('2d'); 
      context.clearRect(0, 0, square, square); 
      var imageWidth; 
      var imageHeight; 
      var offsetX = 0; 
      var offsetY = 0; 

      if (this.width > this.height) { 
       imageWidth = Math.round(square * this.width/this.height); 
       imageHeight = square; 
       offsetX = - Math.round((imageWidth - square)/2); 
      } else { 
       imageHeight = Math.round(square * this.height/this.width); 
       imageWidth = square;  
       offsetY = - Math.round((imageHeight - square)/2);    
      } 

      context.drawImage(this, offsetX, offsetY, imageWidth, imageHeight); 
      var data = canvas.toDataURL('image/jpeg'); 

      var thumb = $('<img/>'); 
      thumb.attr('src', data); 
      $('body').append(thumb); 
     }); 
     image.attr('src', e.target.result); 
    }; 
    reader.readAsDataURL(file); 
}); 
+0

Ho provato 1.2M foto sul mio codice e problema è lo stesso. Puoi verificarlo su http://orientation.gokercebeci.com –

+0

Ho appena colpito questo. Potete crederci!?! – zaf

+7

Questo problema è stato risolto su iPhone4 con iOS 7, ma è interessante notare che il problema non è stato risolto su iPhone5C con iOS 7 ed è in effetti molto peggiore di prima. –

risposta

30

C'è una biblioteca di tela di ridimensionamento JavaScript che lavora attorno alle tematiche sottocampionamento e squash verticale incontrate in sede di elaborazione di immagini scalate su tela su dispositivi iOS: http://github.com/stomita/ios-imagefile-megapixel

Ci sono questioni collaterali durante il ridimensionamento immagini con canale alfa (come utilizza il canale alfa per il rilevamento dei problemi) e quando si tenta di ridimensionare gli elementi canvas esistenti, tuttavia è la prima soluzione che ho trovato che funziona effettivamente con il problema in questione.

stomita è anche un utente StackOverflow e ha postato la sua soluzione qui: https://stackoverflow.com/a/12615436/644048

+0

Creata una demo online di un altro widget di caricamento file che ho appena scritto. Può rilevare il problema di rendering di iOS. Nel caso in cui l'immagine non sembra essere stata renderizzata correttamente, l'immagine viene rieseguita con una correzione applicata. Raddoppiare la scala di altezza di due sembra aggiustarlo anche ... http://sandbox.juurlink.org/html5imageuploader/ –

+0

Ho provato la soluzione di stomita e funziona. Tuttavia, quando eseguo la sua libreria e viene visualizzata l'immagine, come faccio ad accedere a quel contesto di canvas per eseguire ulteriormente l'elaborazione delle immagini su di esso? – Chaz

+0

+1 per credito e collegamento, gj. – Xyon

6

Sembra che questo è un bug di iOS 6. Non c'è motivo per l'aspetto di uscire dal tuo codice. Ho lo stesso problema che è stato introdotto solo in iOS 6. Sembra che la loro routine di sottocampionamento dia l'altezza sbagliata. Ho inviato un bug report ad Apple, e tu dovresti fare lo stesso. Più segnalazioni di bug ottengono per questo, meglio è.

+1

Ho inviato una segnalazione di bug ad Apple per questo problema di squash. –

+0

Si prega di collegare bug. –

+1

Ecco l'esempio che ho inviato a apple: http://evsjupiter.com/canvas.htm – Torchify

51

Se hai ancora bisogno di utilizzare la versione lunga della funzione drawImage è possibile modificare questa:

context.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh); 

a questo:

drawImageIOSFix(context, img, sx, sy, sw, sh, dx, dy, dw, dh); 

Hai solo bisogno di includere queste due funzioni da qualche parte:

/** 
* Detecting vertical squash in loaded image. 
* Fixes a bug which squash image vertically while drawing into canvas for some images. 
* This is a bug in iOS6 devices. This function from https://github.com/stomita/ios-imagefile-megapixel 
* 
*/ 
function detectVerticalSquash(img) { 
    var iw = img.naturalWidth, ih = img.naturalHeight; 
    var canvas = document.createElement('canvas'); 
    canvas.width = 1; 
    canvas.height = ih; 
    var ctx = canvas.getContext('2d'); 
    ctx.drawImage(img, 0, 0); 
    var data = ctx.getImageData(0, 0, 1, ih).data; 
    // search image edge pixel position in case it is squashed vertically. 
    var sy = 0; 
    var ey = ih; 
    var py = ih; 
    while (py > sy) { 
     var alpha = data[(py - 1) * 4 + 3]; 
     if (alpha === 0) { 
      ey = py; 
     } else { 
      sy = py; 
     } 
     py = (ey + sy) >> 1; 
    } 
    var ratio = (py/ih); 
    return (ratio===0)?1:ratio; 
} 

/** 
* A replacement for context.drawImage 
* (args are for source and destination). 
*/ 
function drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { 
    var vertSquashRatio = detectVerticalSquash(img); 
// Works only if whole image is displayed: 
// ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh/vertSquashRatio); 
// The following works correct also when only a part of the image is displayed: 
    ctx.drawImage(img, sx * vertSquashRatio, sy * vertSquashRatio, 
         sw * vertSquashRatio, sh * vertSquashRatio, 
         dx, dy, dw, dh); 
} 

Questo funzionerà bene se è eseguito su iOS o altre piattaforme.

Questo è basato sull'ottimo lavoro di stomita e dovresti riconoscerlo nel tuo lavoro.

+1

La soluzione di cui sopra risolve il problema dello squishing verticale in iOS 7. Dovrei notare che megapixel-image.js, su cui questo codice è basato, per qualche motivo non funziona con iOS 7 ma questo fa. Ora se riesco a trovare una soluzione al problema dell'orientamento, verrò impostato. –

+1

Correzione impressionante. Ho creato una funzione che applica questa correzione a un'istanza di canvas specifica, in modo da poter utilizzare tutte le tue chiamate di riquadri di contesto. Forse è utile a qualcun altro? http://jsfiddle.net/gWY2a/24/ – L0LN1NJ4

+0

@ L0LN1NJ4 Vedo che stai sovrascrivendo la funzione drawimage con la tua implementazione. Grazie per aver condiviso –

-1

Una versione modificata del codice precedente.

Edit: ha visto il codice di L0LN1NJ4 a http://jsfiddle.net/gWY2a/24/ .. immagino che uno è un po 'meglio ...

function drawImageIOSFix (ctx, img) { 
var vertSquashRatio = detectVerticalSquash (img) 
var arg_count = arguments.length 
switch (arg_count) { 
    case 4 : ctx.drawImage (img, arguments[2], arguments[3]/vertSquashRatio); break 
    case 6 : ctx.drawImage (img, arguments[2], arguments[3], arguments[4], arguments[5]/vertSquashRatio); break 
    case 8 : ctx.drawImage (img, arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]/vertSquashRatio); break 
    case 10 : ctx.drawImage (img, arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9]/vertSquashRatio); break 
} 

// Detects vertical squash in loaded image. 
// Fixes a bug which squash image vertically while drawing into canvas for some images. 
// This is a bug in iOS6 (and IOS7) devices. This function from https://github.com/stomita/ios-imagefile-megapixel 
function detectVerticalSquash (img) { 
    var iw = img.naturalWidth, ih = img.naturalHeight 
    var canvas = document.createElement ("canvas") 
    canvas.width = 1 
    canvas.height = ih 
    var ctx = canvas.getContext('2d') 
    ctx.drawImage (img, 0, 0) 
    var data = ctx.getImageData(0, 0, 1, ih).data 
    // search image edge pixel position in case it is squashed vertically. 
    var sy = 0, ey = ih, py = ih 
    while (py > sy) { 
    var alpha = data[(py - 1) * 4 + 3] 
    if (alpha === 0) {ey = py} else {sy = py} 
    py = (ey + sy) >> 1 
    } 
    var ratio = (py/ih) 
    return (ratio === 0) ? 1 : ratio 
} 
} 
+0

Questa non è una risposta, avrebbe dovuto essere un commento. Per favore non trattare le risposte come i messaggi del forum! Leggi le regole di StackOverflow. – Soviut

+0

Hai ragione. Ho aggiunto invece del codice. – Agamemnus