title: Fixing the ios7 squished image in canvas, with rotation and scaling
body: <p>I am having problems with images being squished in iOS7 using canvas.  I have found the following post which seems to be headed in the right direction:</p>
  
  <p><a href="https://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios">HTML5 Canvas drawImage ratio bug iOS</a></p>
  
  <p>However, I am beyond the simple case of drawing an image, I am also rotating and scaling the context (for thumbnails with EXIF orientation data) before drawing the image.  The code runs, but there is no image data in my thumbnails.  I'm guessing this has to do with the canvas rotation and scaling.  However, I'm having a hard time understanding why the thumbnail does not create properly when my squish factor is 1 (on an iOS device that does not have the bug).</p>
  
  <p>Here is my full "onload()" code:</p>
  
  <pre><code>        reader.onloadend = function(evt) {
              console.log('read file data!');
              var tempImg = new Image();
              console.log('created new Image');
              tempImg.src = evt.target.result;
              console.log('set canvas to file');
              // alert(this);
              tempImg.onload = function() {
                console.log('loaded tempImg');
                var MAX_WIDTH = 450;
                var MAX_HEIGHT = 450;
                var tempW = tempImg.width;
                var tempH = tempImg.height;
                if (tempW &gt; tempH) {
                  if (tempW &gt; MAX_WIDTH) {
                     tempH *= MAX_WIDTH / tempW;
                     tempW = MAX_WIDTH;
                  }
                } else {
                  if (tempH &gt; MAX_HEIGHT) {
                     tempW *= MAX_HEIGHT / tempH;
                     tempH = MAX_HEIGHT;
                  }
                      }
  
                var canvas = document.createElement('canvas');
                canvas.width = tempW;
                canvas.height = tempH;
                var ctx = canvas.getContext("2d");
                              // save the current co-ordinate system 
                              // before we screw with it
                              ctx.save(); 
  
                              // move to the middle of where we want to draw our image
                              ctx.translate(tempW/2, tempH/2);
  
                  if (exifTags.hasOwnProperty('Orientation')) {
                          // EXIF FORMAT: 0x0112  Orientation int16u  IFD0    
                                  // 1 = Horizontal (normal) 
                                  // 2 = Mirror horizontal 
                                  // 3 = Rotate 180 
                                  // 4 = Mirror vertical 
                                  // 5 = Mirror horizontal and rotate 270 CW 
                                  // 6 = Rotate 90 CW 
                                  // 7 = Mirror horizontal and rotate 90 CW 
                                  // 8 = Rotate 270 CW
  
                                  // Working.  See: http://creativejs.com/2012/01/day-10-drawing-rotated-images-into-canvas/
  
                    if (exifTags.Orientation == 2) {
                                      console.log('orientation: 2 = Mirror horizontal')
                                      // flip context horizontally
                                      // ctx.translate
                              ctx.scale(-1, 1);
                    } else if (exifTags.Orientation == 3) {
                                      console.log('orientation: 3 = Rotate 180')
                      ctx.rotate(180*Math.PI/180);
                    } else if (exifTags.Orientation == 4) {
                                      console.log('orientation: 4 = Mirror vertical')
                      // flip context vertically
                              ctx.scale(1, -1);
                              } else if (exifTags.Orientation == 5) {
                                      console.log('orientation: Mirror horizontal and rotate 270 CW')
                      // flip context horizontally
                    ctx.rotate(270*Math.PI/180);
                                  ctx.scale(-1, 1);
                    } else if (exifTags.Orientation == 6) {
                                      console.log('orientation: Rotate 90 CW')
                      ctx.rotate(90*Math.PI/180);
                    } else if (exifTags.Orientation == 7) {
                                      console.log('orientation: Mirror horizontal and rotate 90 CW')
                    // flip context horizontally
                                  ctx.rotate(90*Math.PI/180);
                                  ctx.scale(-1, 1);
                    } else if (exifTags.Orientation == 8) {
                                      console.log('orientation: Rotate 270 CW')
                      ctx.rotate(270*Math.PI/180);
                    } else {
                      console.log('unknown orientation: ' + exifTags.Orientation);
                  }
                }
  
                var myImage = this;
  
                if ($scope.platform == "iOS") {
                   /* 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 &gt; sy) {
                          var alpha = data[(py - 1) * 4 + 3];
                          if (alpha === 0) {
                              ey = py;
                          } else {
                              sy = py;
                          }
                          py = (ey + sy) &gt;&gt; 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);
                      console.log('ratio: ' + vertSquashRatio);
  
                     // 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 );                    
                  }
                  console.log('image to unsquish', myImage);
                  // draw it up and to the left by half the width
                  // and height of the image 
  
                  drawImageIOSFix(ctx, myImage, -tempW/2, -tempH/2, tempW, tempH);
  
                } else {
                  // draw it up and to the left by half the width
                  // and height of the image 
                  ctx.drawImage(myImage, -tempW/2, -tempH/2, tempW, tempH);
                }
  
                // and restore the co-ords to how they were when we began
                ctx.restore(); 
                var dataURL = canvas.toDataURL();
                // alert('created image!');
  
                var fileName = undefined;
  
                if ($scope.platform == "iOS") {
                  // Store only the name for iOS, hard paths are unreliable
  
                  var timestamp = new Date().getTime();
                  fileName = timestamp.toString().concat('t.jpg');
                  var thumbPath = fileSystem.root.toURL() + "/STL/" + fileName;
                  var thumbName = "/STL/" + fileName;
  
                } else {
  
                  var name = file.name
                  var position = name.length-4 
                  fileName = name.substr(0, position) + 't.jpg';
                  var thumbPath = fileSystem.root.toURL() + "/.STL/" + thumbName;
                  var thumbName = fileName;  
                }
  
  
                $scope.mediaCollection.thumbNames.push(thumbName);
                $scope.mediaCollection.thumbPaths.push(thumbPath);
                $scope.mediaCollection.exifData.push(exifTags);
                $scope.mediaCollection.Orientation.push(exifTags.Orientation);
  
                canvas.toBlob(function(blob){
                  console.log(blob.size + ':' + blob.type);                          
                  function newFile(fileEntry){
                    console.log('created new fileEntry');
                    fileEntry.createWriter(gotFileWriter, fail);
                  }
  
                  function gotFileWriter(writer) {
                    console.log('got fileWriter');
                    writer.seek(0);
  
                    // window.location = blobUrl;
                    writer.write(blob);
                    console.log('wrote blob!');
                    writeIfReady();
                  }
  
                  console.log('about to get Directory');
                  console.log('fileSystem root: ', fileSystem.root, $scope.iOS_FS);
                  console.log('platform: ', $scope.platform);
  
                  // can replace if/else with single request using $scope.STL_dir
                  if ($scope.platform = "iOS") {
                    // May need maintenance... 
                    fileSystem.root.getDirectory('STL', {create: true}, function(dirEntry) {
                      console.log('got directory, about to create thumbnail file: ' + fileName);
                      dirEntry.getFile(fileName, {create: true, exclusive: true}, newFile, fail);
                    }, fail);
                  } else {
                    fileSystem.root.getDirectory('.STL', {create: true}, function(dirEntry) {
                      dirEntry.getFile(fileName, {create: true, exclusive: true}, newFile, fail);
                    }, fail);                      
                  }
  
                }, "image/jpg");
  
              }
            }
  </code></pre>