Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Image squished in iOS6 upload when resizing #631

Closed
jewel opened this Issue Oct 8, 2012 · 20 comments

Comments

Projects
None yet
9 participants

jewel commented Oct 8, 2012

If an image is uploaded through mobile Safari on iOS6, it will be squished and a black bar will take up the remaining space. This seems to be a bug in Safari.

Original image: http://thesteve.org/up/IMG_0001.JPG
Resized: http://thesteve.org/up/image.jpg.3a5e900954c08e64b123633d6a3f0210.jpg

This isn't a bug in plupload, but plupload will probably have to ship a workaround for the issue. I will update this ticket with a workaround if I can discover one.

edwh commented Oct 10, 2012

I'm also seeing this. An example image is at https://direct.ilovefreegle.org/uploads/p17935j7131t5l2ql87a1oehkn3.jpg .

Jojjes commented Oct 23, 2012

I am also seeing this problem on iphone/ios6. Any ideas on how to solve this?

edwh commented Nov 11, 2012

Anyone got a fix or a workaround?

jewel commented Nov 11, 2012

@edwh We switched to https://github.com/protonet/plupload which fixed both this issue and #623.

edwh commented Nov 11, 2012

Thanks. Is that another fork of the same code, i.e. the same interface?

On 11/11/2012 4:28 PM, Jewel wrote:

@edwh https://github.com/edwh We switched to
https://github.com/protonet/plupload which fixed both this issue and
#623 #623.


Reply to this email directly or view it on GitHub
#631 (comment).

Owner

jayarjo commented Dec 23, 2012

@jewel, I do not see how the fork you mention fixes squish bug, does it?

edwh commented Dec 23, 2012

It didn't fix it for me.

On 23/12/2012 5:55 PM, Davit Barbakadze wrote:

@jewel https://github.com/jewel, I do not see how the fork you
mention fixes squish bug, does it?


Reply to this email directly or view it on GitHub
#631 (comment).

jewel commented Dec 23, 2012

@edwh @jayarjo My sincerest apologies, you're both right. We worked around the issue by not resizing on iOS.

edwh commented Dec 23, 2012

I'm shocked to say that hadn't occurred to me. Dear me.

On 23/12/2012 6:20 PM, Jewel wrote:

@edwh https://github.com/edwh @jayarjo https://github.com/jayarjo
My sincerest apologies, you're both right. We worked around the issue
by not resizing on iOS.


Reply to this email directly or view it on GitHub
#631 (comment).

Also seeing the iOS6 squish bug when resizing - but only on the iPad 4, not the iPhone 4. The iOS image fix mentioned in the code has fixed the multiple uploads failing seen in version 1.5.

We're facing the same problems. Photos taken as part of the image upload process gets squished and a black bar occurs. Same behavior on both iPhone and IPad (iOS 6). Tried both ver 1.x and Beta 2 versions of Plupload.

Simply not re-sizing the image client-side for iOS devices is not the solution I was hoping for, but it's surely a work-around.

Webkit gurus - is there really no other way to solve this client-side?

@FredrikRofors See the top comment for a solution

@sandstrom Thx for taking time to answer.

Are you talking about replacing Plupload entirely or somehow hooking megapix-image.js library into it?

huan086 commented Mar 5, 2013

I've created a patch for the html5 runtime to fix the issue. The fix integrates the MegaPixel code that sandstrom mentioned

--- plupload.html5.orig.js  Tue Mar  5 17:05:46 2013
+++ plupload.html5.js   Tue Mar  5 17:04:53 2013
@@ -1,4 +1,6 @@
 /**
+ * https://raw.github.com/moxiecode/plupload/1.x/src/javascript/plupload.html5.js
+ * https://github.com/moxiecode/plupload/issues/631
  * plupload.html5.js
  *
  * Copyright 2009, Moxiecode Systems AB
@@ -12,6 +14,100 @@
 /*global plupload:false, File:false, window:false, atob:false, FormData:false, FileReader:false, ArrayBuffer:false, Uint8Array:false, BlobBuilder:false, unescape:false */

 (function (window, document, plupload, undef) {
+    // Jeow Li Huan: to fix iOS vertical photo being squashed.
+    /**
+     * Detect subsampling in loaded image.
+     * In iOS, larger images than 2M pixels may be subsampled in rendering.
+     */
+    function detectSubsampling(img) {
+        var iw = img.naturalWidth, ih = img.naturalHeight;
+        if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image
+            var canvas = document.createElement('canvas');
+            canvas.width = canvas.height = 1;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, -iw + 1, 0);
+            // subsampled image becomes half smaller in rendering size.
+            // check alpha channel value to confirm image is covering edge pixel or not.
+            // if alpha value is 0 image is not covering, hence subsampled.
+            return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Detecting vertical squash in loaded image.
+     * Fixes a bug which squash image vertically while drawing into canvas for some images.
+     */
+    function detectVerticalSquash(img, iw, ih) {
+        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;
+    }
+
+    /**
+     * Rendering image element (with resizing) into the canvas element
+     */
+    function renderImageToCanvas(img, canvas, options) {
+        var iw = img.naturalWidth, ih = img.naturalHeight;
+        var width = options.width, height = options.height;
+        var ctx = canvas.getContext('2d');
+        ctx.save();
+        var subsampled = detectSubsampling(img);
+        if (subsampled) {
+            iw /= 2;
+            ih /= 2;
+        }
+
+        var d = 1024; // size of tiling canvas
+        var tmpCanvas = document.createElement('canvas');
+        tmpCanvas.width = tmpCanvas.height = d;
+        var tmpCtx = tmpCanvas.getContext('2d');
+        var vertSquashRatio = detectVerticalSquash(img, iw, ih);
+        var sy = 0;
+        while (sy < ih) {
+            var sh = sy + d > ih ? ih - sy : d;
+            var sx = 0;
+            while (sx < iw) {
+                var sw = sx + d > iw ? iw - sx : d;
+                tmpCtx.clearRect(0, 0, d, d);
+                tmpCtx.drawImage(img, -sx, -sy);
+                var dx = (sx * width / iw) << 0;
+                var dw = Math.ceil(sw * width / iw);
+                var dy = (sy * height / ih / vertSquashRatio) << 0;
+                var dh = Math.ceil(sh * height / ih / vertSquashRatio);
+                ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh);
+                sx += d;
+            }
+
+            sy += d;
+        }
+
+        ctx.restore();
+        tmpCanvas = tmpCtx = null;
+    }
+    // End to fix iOS vertical photo being squashed.
+
     var html5files = {}, // queue of original File objects
    fakeSafariDragDrop;

@@ -54,8 +150,10 @@
             canvas = document.createElement("canvas");
             canvas.style.display = 'none';
             document.body.appendChild(canvas);
-            context = canvas.getContext('2d');

+            // Jeow Li Huan: to fix iOS vertical photo being squashed.
+            ////context = canvas.getContext('2d');
+
             // Load image
             img = new Image();
             img.onerror = img.onabort = function () {
@@ -91,7 +189,9 @@
                 // Scale image and canvas
                 canvas.width = width;
                 canvas.height = height;
-                context.drawImage(img, 0, 0, width, height);
+                // Jeow Li Huan: to fix iOS vertical photo being squashed.
+                renderImageToCanvas(img, canvas, { width: width, height: height });
+                ////context.drawImage(img, 0, 0, width, height);

                 // Preserve JPEG headers
                 if (mime === 'image/jpeg') {
@@ -204,7 +304,7 @@
                 chunks: sliceSupport,
                 // Safari on Windows has problems when selecting multiple files
                 multi_selection: !(plupload.ua.safari && plupload.ua.windows),
-                // WebKit and Gecko 2+ can trigger file dialog progrmmatically
+                // WebKit and Gecko 2+ can trigger file dialog programmatically
                 triggerDialog: (plupload.ua.gecko && window.FormData || plupload.ua.webkit)
             };
         },
@@ -514,10 +614,10 @@

                     if (File.prototype.slice) {
                         try {
-                            blob.slice();  // depricated version will throw WRONG_ARGUMENTS_ERR exception
+                            blob.slice();  // deprecated version will throw WRONG_ARGUMENTS_ERR exception
                             return blob.slice(start, end);
                         } catch (e) {
-                            // depricated slice method
+                            // deprecated slice method
                             return blob.slice(start, end - start);
                         }
                         // slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672  

Edit: lol. I'm still leaving in the SVN era, sending a .diff. Made my first pull request below.

@huan086 Sounds great! As far I interpret your comment you have forked https://github.com/moxiecode/plupload/ and applied your fix to a private repository, am I right? (cause I can't see any fix commit on neither the 1.x or the master branch). If so, have you issued a pull-request to the guys at Moxiecode?

This is not a fix -- it's a work around or hack...for the Plupload2 beta -- more fully explained in http://www.plupload.com/punbb/viewtopic.php?pid=11802#p11802

  1. include Megapix_image library suggested by sandstrom in your ios6 upload page
  2. Currently on line 7438 of moxie.js the following code would need to be added; (in the _resize function immediately after the _canvas is created)

//...
if (!_canvas) {
_canvas = document.createElement("canvas");
}

... new code starts here - use MegaPixelImage if installed
if (typeof MegaPixImage == 'function') {
var _tmp = new MegaPixImage(_img);
_tmp.render(_canvas, {width:imgWidth,height:imgHeight,quality:0.9});
_modified = true;
_img = _tmp;

this.trigger('Resize', {
     width: crop ? width : imgWidth,
     height: crop ? height : imgHeight
});
return;

}
... else fall back to original code
//...

@jayarjo jayarjo closed this in e333638 Mar 7, 2013

Just for the record...
I applied @aliwatters suggested hack to the Plupload2 beta code...and drum rolls ...it works perfectly (tested on iOS 6.1.2 devices).

Thx guys for your effort!

Owner

jayarjo commented Mar 19, 2013

Something similar is already in the core, although not yet in any build. But will be these days.

@huan086 thx so so so much for this fix! saved me a huge headache!

yansern pushed a commit to foundry-modules/plupload that referenced this issue Feb 18, 2014

madmaker added a commit to madmaker/plupload that referenced this issue Jan 23, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment