ICEfaces
  1. ICEfaces
  2. ICE-10447

mobi:camera - add HTML5 getUserMedia Support

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: EE-4.0.0.GA
    • Component/s: MOBI-Components
    • Labels:
      None
    • Environment:
      ICEmobile EE 1.3.1
    • Assignee Priority:
      P2
    • Affects:
      Compatibility/Configuration

      Description

      Enhancement of the ICEmobile Camera component with HTML5 getUserMedia support

          The Camera component will dynamically render JavaScript code for an HTML5 fallback mode when BridgeIt Native utility app is not available or not present
          The HTML5 fallback mode will do client-side detection of the getUserMedia API
              If the API is not present, the component will render an input file element as before
              If the API is present, the component will render a button to trigger the getUserMedia API and a simulated camera capture popup
          Simulated Camera Capture popup
              Will show the user the video capture stream from within the web application
              Will provide a capture button to take a photo
              Will provide a thumbnail of the captured image using an HTML5 canvas element
              Will allow the user to select the current image, or take another photo
              If possible, the image data may be stored in local storage until the form is posted
              The selected image will be serialized into the form so that it can be uploaded on the next form post
          The server-side mobi:camera component API will remain unchanged, if possible.

        Activity

        Hide
        Philip Breau added a comment - - edited

        IM 1.3.1 camera rendering logic (without Shim support):

        Server

        • if BridgeIt app registered
          • render button with onclick script for BridgeIt native camera
        • else
          • render button with onclick script for dynamic getUserMedia detection (ice.mobi.fallbackCamera())

        Client button onclick handler

        • if getUserMedia supported
          • create popup with video element
          • fire getUserMedia()
          • direct video stream to video element
          • show 'take picture' button
        • else
          • render a file upload element with HTML5 accept and capture attributes,
            • eg. accept='images/*;capture=camera', capture='true'

        Client getUserMedia image capture handler

        • create canvas element
        • create img element
        • canvas.getContext('2d').drawImage(video)
        • draw img element with base64 data url
        • show 'keep' and 'redo' buttons

        Client image capture from canvas element

        • create hidden input element
        • set hidden input element value with img element data url data

        Current IF 4 Camera rendering logic:

        Server

        • render button with bridgeit.camera() handler

        BridgeIt camera onclick handler

        • call native BridgeIt utility app
        • if native call fails, call bridgeit.launchFailed() callback hook

        Proposed IF 4 Camera rendering logic:

        Server

        • render button with onclick ice.mobi.cameraBtnOnClick handler

        Client cameraBtnOnClick handler

        • call bridgeit.camera() with custom cameraLaunchFailed callback

        cameraLaunchFailed callback

        • if getUserMedia supported
          • create popup with video element
          • fire getUserMedia()
          • direct video stream to video element
          • show 'take picture' button
        • else
          • render a file upload element with HTML5 accept and capture attributes,
            • eg. accept='images/*;capture=camera', capture='true'
        Show
        Philip Breau added a comment - - edited IM 1.3.1 camera rendering logic (without Shim support): Server if BridgeIt app registered render button with onclick script for BridgeIt native camera else render button with onclick script for dynamic getUserMedia detection (ice.mobi.fallbackCamera()) Client button onclick handler if getUserMedia supported create popup with video element fire getUserMedia() direct video stream to video element show 'take picture' button else render a file upload element with HTML5 accept and capture attributes, eg. accept='images/*;capture=camera', capture='true' Client getUserMedia image capture handler create canvas element create img element canvas.getContext('2d').drawImage(video) draw img element with base64 data url show 'keep' and 'redo' buttons Client image capture from canvas element create hidden input element set hidden input element value with img element data url data Current IF 4 Camera rendering logic: Server render button with bridgeit.camera() handler BridgeIt camera onclick handler call native BridgeIt utility app if native call fails, call bridgeit.launchFailed() callback hook Proposed IF 4 Camera rendering logic: Server render button with onclick ice.mobi.cameraBtnOnClick handler Client cameraBtnOnClick handler call bridgeit.camera() with custom cameraLaunchFailed callback cameraLaunchFailed callback if getUserMedia supported create popup with video element fire getUserMedia() direct video stream to video element show 'take picture' button else render a file upload element with HTML5 accept and capture attributes, eg. accept='images/*;capture=camera', capture='true'
        Hide
        Ken Fyten added a comment -

        Note that testing in Safari (desktop) shows that the camera function fails with the attached JS error ("undefined function Navigator.getUserMedia...").

        Show
        Ken Fyten added a comment - Note that testing in Safari (desktop) shows that the camera function fails with the attached JS error ("undefined function Navigator.getUserMedia...").
        Hide
        Philip Breau added a comment -

        Component no longer requires multipart form when falling back to file upload. Thumbnail is now also updated when using the file upload fallback version.

        Show
        Philip Breau added a comment - Component no longer requires multipart form when falling back to file upload. Thumbnail is now also updated when using the file upload fallback version.
        Hide
        Ken Fyten added a comment - - edited

        Philip, my testing today identified the following apparent issues with the updated mobi:camera:

        1. Capture message label does not update on Firefox (works on Safari and Chrome). Is this just a browser support issue / known issue?
        2. Larger images fail on all browsers with Connection Interrupted (1MB+? image files). Any thoughts on why this might be (this when uploading via fileUpload mode)?
        3. Also, the thumbnail resets to an error image icon after the first captured/selected image is uploaded. Subsequent captures/selections work fine and the thumbnail continues to show the captured image after the upload. Would this be a straight thumbnail component issue, or a showcase app. issue of some kind?

        Also, is there a way style the popup camera dialog in terms of size, location, fonts, button padding, etc.?

        Show
        Ken Fyten added a comment - - edited Philip, my testing today identified the following apparent issues with the updated mobi:camera: Capture message label does not update on Firefox (works on Safari and Chrome). Is this just a browser support issue / known issue? Larger images fail on all browsers with Connection Interrupted (1MB+? image files). Any thoughts on why this might be (this when uploading via fileUpload mode)? Also, the thumbnail resets to an error image icon after the first captured/selected image is uploaded. Subsequent captures/selections work fine and the thumbnail continues to show the captured image after the upload. Would this be a straight thumbnail component issue, or a showcase app. issue of some kind? Also, is there a way style the popup camera dialog in terms of size, location, fonts, button padding, etc.?
        Hide
        Philip Breau added a comment -
        • client side JPEG encoder added for processing image files
        • a sliding scale of image resolution is used depending on the file size
        • this dramatically shrinks down file size < 500k
        • note that form posts exceeding certain values may still be rejecte by the server. For Tomcat, set the connector maxPostSize accordingly, or disable it with a value of 0
        • the thumbnail renderer regression has also been corrected
        Show
        Philip Breau added a comment - client side JPEG encoder added for processing image files a sliding scale of image resolution is used depending on the file size this dramatically shrinks down file size < 500k note that form posts exceeding certain values may still be rejecte by the server. For Tomcat, set the connector maxPostSize accordingly, or disable it with a value of 0 the thumbnail renderer regression has also been corrected
        Hide
        Ken Fyten added a comment -

        Testing shows the following:

        • On Firefox, selecting a larger image to upload (>1MB) takes a long time and usually causes a long-running script error dialog to show, if you press continue it does eventually complete. However, the resulting image is generally greatly degraded to a point that would be unacceptable for most uses.
        • On Firefox only, the first time you submit a photo that was taken via the camera (not a file upload from the file system), the thumbnail is lost and replaced with a broken image icon. Subsequent image captures work fine, as do all file uploads.

        I do not think that using the client-side image processing approach is going to work as it degrades the image quality without any control or config. available to the application. So long as the server can be configured to accept larger uploads, I think we should remove it and we can document the need to configure the server accordingly. This way the image quality will remain that of the original upload.

        Show
        Ken Fyten added a comment - Testing shows the following: On Firefox, selecting a larger image to upload (>1MB) takes a long time and usually causes a long-running script error dialog to show, if you press continue it does eventually complete. However, the resulting image is generally greatly degraded to a point that would be unacceptable for most uses. On Firefox only, the first time you submit a photo that was taken via the camera (not a file upload from the file system), the thumbnail is lost and replaced with a broken image icon. Subsequent image captures work fine, as do all file uploads. I do not think that using the client-side image processing approach is going to work as it degrades the image quality without any control or config. available to the application. So long as the server can be configured to accept larger uploads, I think we should remove it and we can document the need to configure the server accordingly. This way the image quality will remain that of the original upload.
        Hide
        Ken Fyten added a comment -

        QA has found the following issues on the iOS Safari browser with this version of the component as well:

        The image cannot be uploaded. Fails with "The uploaded image file could not be correctly processed.".

        Show
        Ken Fyten added a comment - QA has found the following issues on the iOS Safari browser with this version of the component as well: The image cannot be uploaded. Fails with "The uploaded image file could not be correctly processed.".
        Hide
        Philip Breau added a comment -

        I removed the client side JPEG encoder and retested on all browsers. The image processing is now faster. On Chrome I recorded the following times for a jpg image of ~3.2mb:

        • load image file 28ms
        • create Image object 1000ms
        • create data URLs for thumbnail and image upload with canvs 8500ms

        This is noticably faster than using the jpeg encoder.

        But this creates a worse problem. The Canvas.toDataURL() implementations on all browsers default to creating an png file, and ignore the directive to encode to jpg, which would a reductiion in resolution for the thumbnail and a much smaller image file overall. The resulting png data url is approximately 10X the size of a jpg file. So a 3mb original jpg file will result in a 30mb png file. And uploading the 30mb png then locks up almost all browsers.

        So I don't think we have a choice but to scale larger image files. I've checked in a version that uses a scaling factor for images larger than 1mb and this seems to work well with reasonable performance on all desktop browsers. Scaling is done with Canvas and little loss of effective screen resolution is seen.

        Show
        Philip Breau added a comment - I removed the client side JPEG encoder and retested on all browsers. The image processing is now faster. On Chrome I recorded the following times for a jpg image of ~3.2mb: load image file 28ms create Image object 1000ms create data URLs for thumbnail and image upload with canvs 8500ms This is noticably faster than using the jpeg encoder. But this creates a worse problem. The Canvas.toDataURL() implementations on all browsers default to creating an png file, and ignore the directive to encode to jpg, which would a reductiion in resolution for the thumbnail and a much smaller image file overall. The resulting png data url is approximately 10X the size of a jpg file. So a 3mb original jpg file will result in a 30mb png file. And uploading the 30mb png then locks up almost all browsers. So I don't think we have a choice but to scale larger image files. I've checked in a version that uses a scaling factor for images larger than 1mb and this seems to work well with reasonable performance on all desktop browsers. Scaling is done with Canvas and little loss of effective screen resolution is seen.
        Hide
        Ken Fyten added a comment -

        Sorry Philip, testing on svn rvn# 44097 I'm seeing the following failures:

        1. On desktop browsers, any file larger than 1MB fails immediately upon upload with a Network Connection Interrupted error. Smaller files work correctly.
        2. On iphone 5 / iOS8.1.3, taking a picture works (via BridgeIt), the thumbnail shows up, but uploading fails with "The uploaded image file could not be correctly processed."
        Show
        Ken Fyten added a comment - Sorry Philip, testing on svn rvn# 44097 I'm seeing the following failures: On desktop browsers, any file larger than 1MB fails immediately upon upload with a Network Connection Interrupted error. Smaller files work correctly. On iphone 5 / iOS8.1.3, taking a picture works (via BridgeIt), the thumbnail shows up, but uploading fails with "The uploaded image file could not be correctly processed."
        Hide
        Philip Breau added a comment -

        Ken,
        I can't reproduce the issue with the file upload. I've tested jenkins build #182 with Tomcat 7.0.42 (with post size limit increased) and Win 7 (Chrome 40, FF 35, IE 11), and Mac (Chrome 40 and Safari 8.0.3) and all them succeed processing and posting a 3.2mb jpg file. Have you tried different image files?

        I did notice that the post is including a large thumbnail data url. I'll fix that which should reduce the the post size by about half.

        Show
        Philip Breau added a comment - Ken, I can't reproduce the issue with the file upload. I've tested jenkins build #182 with Tomcat 7.0.42 (with post size limit increased) and Win 7 (Chrome 40, FF 35, IE 11), and Mac (Chrome 40 and Safari 8.0.3) and all them succeed processing and posting a 3.2mb jpg file. Have you tried different image files? I did notice that the post is including a large thumbnail data url. I'll fix that which should reduce the the post size by about half.
        Hide
        Ken Fyten added a comment -

        Testing using Jenkins ICEfaces 4 continuous build (http://dev.icesoft.com/jenkins/job/ICEfaces%204%20Trunk%20(Continuous)/1075/ / svn rvn# 44100)

        1. On desktop browsers, any file larger than 1MB fails immediately upon upload with a Network Connection Interrupted error. Smaller files work correctly.
          • The following JS errors are seen in the console:
            14:27:09.117 "[window] [Mon, 23 Feb 2015 21:27:09 GMT] the response does not contain XML data" bridge-support.js.jsf:1817
            14:27:09.118 "[window] [Mon, 23 Feb 2015 21:27:09 GMT] HTTP error [code: 0]: The Http Transport returned a 0 status code.  This is usually the result of mixing ajax and full requests.  This is usually undesired, for both performance and data integrity reasons." bridge-support.js.jsf:1817 
        2. On iphone 5 / iOS8.1.3, taking a picture works (via BridgeIt), the thumbnail shows, the upload works, but then the thumbnail is immediately cleared. If I recall correctly, I think it was needing to submit the thumbnail to the server so it could be rendered back out to the client after the submit. This is an app. developer choice. I think it is just as valid to clear the thumbnail after a successful submit, so we can leave it like this. As you mentioned in your commit log, it results in a much smaller sized submit to upload the photo without the thumbnail data.
        Show
        Ken Fyten added a comment - Testing using Jenkins ICEfaces 4 continuous build ( http://dev.icesoft.com/jenkins/job/ICEfaces%204%20Trunk%20(Continuous)/1075/ / svn rvn# 44100) On desktop browsers, any file larger than 1MB fails immediately upon upload with a Network Connection Interrupted error. Smaller files work correctly. The following JS errors are seen in the console: 14:27:09.117 "[window] [Mon, 23 Feb 2015 21:27:09 GMT] the response does not contain XML data" bridge-support.js.jsf:1817 14:27:09.118 "[window] [Mon, 23 Feb 2015 21:27:09 GMT] HTTP error [code: 0]: The Http Transport returned a 0 status code. This is usually the result of mixing ajax and full requests. This is usually undesired, for both performance and data integrity reasons." bridge-support.js.jsf:1817 On iphone 5 / iOS8.1.3, taking a picture works (via BridgeIt), the thumbnail shows, the upload works, but then the thumbnail is immediately cleared. If I recall correctly, I think it was needing to submit the thumbnail to the server so it could be rendered back out to the client after the submit. This is an app. developer choice. I think it is just as valid to clear the thumbnail after a successful submit, so we can leave it like this. As you mentioned in your commit log, it results in a much smaller sized submit to upload the photo without the thumbnail data.
        Hide
        Ken Fyten added a comment - - edited

        From Philip's commit log:

        Change file and canvas uploads to use FormData and submit to Auxillary upload post url.

        Show
        Ken Fyten added a comment - - edited From Philip's commit log: Change file and canvas uploads to use FormData and submit to Auxillary upload post url.

          People

          • Assignee:
            Philip Breau
            Reporter:
            Philip Breau
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: