Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery webcam plugin does not post the captured image

I am using jquery webcam plugin in a MVC4 page. The plugin is here: http://www.xarg.org/project/jquery-webcam-plugin/.

I am using save method on the plugin after capturing the image but it is not posted to the controller action.

This is the cshtml page:

@{
    ViewBag.Title = "Index";
}

<!DOCTYPE html>
<html lang="es">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>@ViewBag.Title - Prueba WebCam</title>
    <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
    <meta name="viewport" content="width=device-width" />
    @Styles.Render("~/styles/base")
    @Scripts.Render("~/scripts/jquery", "~/scripts/jqueryui", "~/scripts/webcam")

    <script type="text/javascript">
        $(function () {
            $("#camera").webcam({
                width: 320,
                height: 240,
                mode: "save",
                swffile: "@Url.Content("~/Scripts/WebCam/jscam_canvas_only.swf")",
                onTick: function () { },
                onSave: function () { alert('Almacenamiento realizado') },
                onCapture: function () { webcam.save("@Url.Action("Save")"); alert('Captura realizada'); },
                debug: function () { },
                onLoad: function () { }
            });
        });

        function CaptureAndSave() {
            webcam.capture();
        }
    </script>
</head>
<body class="home desytec">
    <header>
    </header>
    <!-- MAIN -->
    <div id="main">
        <!-- wrapper-main -->
        <div class="wrapper">
            <!-- headline -->
            <div class="clear"></div>
            <div id="headline">
                <span class="main"></span>
                <span class="sub"></span>
            </div>
            <!-- ENDS headline -->

            <!-- content -->
            <div id="content">
                <div id="camera"></div>
                <br /><br /><br />
                <input type="button" onclick="CaptureAndSave();" value="Capturar" />
            </div>
            <!-- ENDS content -->
        </div>
        <!-- ENDS wrapper-main -->
    </div>
    <!-- ENDS MAIN -->
    <footer>
    </footer>
</body>
</html>

And this is the controller:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Capture.Controllers
{
    public class CaptureController : Controller
    {
        //
        // GET: /Capture/

        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public JsonResult Save(HttpPostedFileBase file)
        {
            try
            {
                if (file != null)
                {
                    string pic = System.IO.Path.GetFileName(file.FileName);
                    string path = System.IO.Path.Combine(Server.MapPath("~/Captures"), pic);
                    file.SaveAs(path);
                    return Json(true, JsonRequestBehavior.AllowGet);
                }
            }
            catch
            {

            }
            return Json(true, JsonRequestBehavior.AllowGet);
        }
    }
}

Save method of the controller get never called and in fact, by using firebug, no POST is done.

By the way. The camera works because I can see the it in the canvas (DIV id = camera).

And OnCapture callback is called after I press the capture button.

Any help on this, please?

Thanks Jaime

like image 646
jstuardo Avatar asked Dec 07 '13 23:12

jstuardo


1 Answers

Your Save action is not called because the jscam_canvas_only.swf only contains the "callback" mode. For the full API (so for the "save" mode) you need download and use the jscam.swf.

So change your webcam setup to:

$("#camera").webcam({
    //...
    swffile: "@Url.Content("~/Scripts/WebCam/jscam.swf")",
    //...
});

Now your Save action will be called but the file parameter will be always null, because the jscam.swf send the image data as hexadecimal string in the request body.

The default model binding infrastructure is not handling this so you need to write some additional code:

if (Request.InputStream.Length > 0)
{
    string pic = System.IO.Path.GetFileName("capture.jpg");
    string path = System.IO.Path.Combine(Server.MapPath("~/Captures"), pic);
    using (var reader = new StreamReader(Request.InputStream))
    {
        System.IO.File.WriteAllBytes(path, StringToByteArray(reader.ReadToEnd()));
    }
    return Json(true, JsonRequestBehavior.AllowGet);
}

You need to remove the file parameter and access the raw data from the Request.InputStream but because it is a hexadecimal string you need to convert it to a byte[] before saving it.

There is no default conversion built in .NET but SO is full of good solutions:

How do you convert Byte Array to Hexadecimal String, and vice versa?

In my sample I've used this method:

public static byte[] StringToByteArray(String hex)
{
  int NumberChars = hex.Length/2;
  byte[] bytes = new byte[NumberChars];
  using (var sr = new StringReader(hex))
  {
    for (int i = 0; i < NumberChars; i++)
      bytes[i] = 
        Convert.ToByte(new string(new char[2]{(char)sr.Read(), (char)sr.Read()}), 16);
  }
  return bytes;
}
like image 51
nemesv Avatar answered Oct 11 '22 18:10

nemesv