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
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;
}