好久没上来看看了,工作有点点忙。
最近有个项目,在手机端实现调用摄像头拍照识别二维码信息。
在网上找了一些资料,放在这里,备忘。
方案一:
用 HTML5 调用摄像头,获取画面然后通过 canvas 拿到图片,在用 zxing 组件识别。
<script type="text/javascript">
var sel, fr;
$(function () {
$('#canvas').hide();
try {
sel = document.getElementById('fileselect'); // get reference to file select input element
window.addEventListener("DOMContentLoaded", function () {
// Grab elements, create settings, etc.
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
video = document.getElementById("video"),
videoObj = { "video": true },
errBack = function (error) {
if (error.PERMISSION_DENIED) {
AlertDialog.Alert("", "用户拒绝了浏览器请求媒体的权限", "");
//AlertDialog.Alert('用户拒绝了浏览器请求媒体的权限', '提示');
} else if (error.NOT_SUPPORTED_ERROR) {
AlertDialog.Alert("", "对不起,您的浏览器不支持拍照功能,请使用其他浏览器", "");
//AlertDialog.Alert('对不起,您的浏览器不支持拍照功能,请使用其他浏览器', '提示');
} else if (error.MANDATORY_UNSATISFIED_ERROR) {
//AlertDialog.Alert('指定的媒体类型未接收到媒体流', '提示');
AlertDialog.Alert("", "指定的媒体类型未接收到媒体流", "");
} else {
AlertDialog.Alert("",'系统未能获取到摄像头,请确保摄像头已正确安装。或尝试刷新页面,重试', "");
}
};
var message = "为了获得更准确的测试结果,请尽量将面部置于红框中,然后进行拍摄、扫描。 点击“OK”后,请在屏幕上方出现的提示框选择“允许”,以开启摄像功能";
// Put video listeners into place
if (navigator.getUserMedia) { // Standard
if (navigator.userAgent.indexOf('MQQBrowser') > -1) {
AlertDialog.Alert("",'对不起,您的浏览器不支持拍照功能,请使用其他浏览器', "");
return false;
}
AlertDialog.AlertAndOkfn("", message, "", false, "", function () {
$(document).scrollTop($(window).height());
});
//AlertDialog.Alert(message, '提示', function () {
// $(document).scrollTop($(window).height());
//});
navigator.getUserMedia(videoObj, function (stream) {
video.src = stream;
video.play();
alert(11);
$('#lifescan #main .btn_click').css('margin-top', '-550px');
video.addEventListener('loadeddata', function () {
$(document).scrollTop($(window).height());
}, false);
$('#snap').click(function () {
//$('.scan-area').show();
$('#cream_loading').toggle();
context.drawImage(video, 0, 0, 640, 480);
convertCanvasToImage();
});
}, errBack);
} else if (navigator.webkitGetUserMedia) { // WebKit-prefixed
AlertDialog.AlertAndOkfn("", message, "", false, "", function () {
$(document).scrollTop($(window).height());
});
//AlertDialog.Alert(message, '提示', function () {
// $(document).scrollTop($(window).height());
//});
navigator.webkitGetUserMedia(videoObj, function (stream) {
video.src = window.webkitURL.createObjectURL(stream);
video.play();
$('#lifescan #main .btn_click').css('margin-top', '-550px');
video.addEventListener('loadeddata', function () {
$(document).scrollTop($(window).height());
}, false);
if (navigator.userAgent.indexOf('UCBrowser') > -1) {
$('#lifescan #main .btn_click').css('margin-top', '-10px');
}
$('#snap').click(function () {
$('#cream_loading').toggle();
context.drawImage(video, 0, 0, 640, 480);
convertCanvasToImage();
});
}, errBack);
}
else if (navigator.mozGetUserMedia) { // Firefox-prefixed
AlertDialog.AlertAndOkfn("", message, "", false, "", function () {
$(document).scrollTop($(window).height());
});
//AlertDialog.Alert(message, '提示', function () {
// $(document).scrollTop($(window).height());
//});
navigator.mozGetUserMedia(videoObj, function (stream) {
video.src = window.URL.createObjectURL(stream);
video.play();
video.addEventListener('loadeddata', function () {
$(document).scrollTop($(window).height());
}, false);
$('#lifescan #main .btn_click').css('margin-top', '-550px');
$('#snap').click(function () {
$('#cream_loading').toggle();
context.drawImage(video, 0, 0, 640, 480);
convertCanvasToImage();
});
}, errBack);
}
else if (navigator.msGetUserMedia) {
AlertDialog.AlertAndOkfn("", message, "", false, "", function () {
$(document).scrollTop($(window).height());
});
//AlertDialog.Alert(message, '提示', function () {
// $(document).scrollTop($(window).height());
//});
navigator.msGetUserMedia(videoObj, function (stream) {
$(document).scrollTop($(window).height());
video.src = window.URL.createObjectURL(stream);
video.play();
$('#lifescan #main .btn_click').css('margin-top', '-550px');
video.addEventListener('loadeddata', function () {
$(document).scrollTop($(window).height());
}, false);
$('#snap').click(function () {
$('#cream_loading').toggle();
context.drawImage(video, 0, 0, 640, 480);
convertCanvasToImage();
});
}, errBack);
}
else {
var userAgent = navigator.userAgent;
if (userAgent.indexOf("Safari") > -1 && userAgent.indexOf("Oupeng") == -1 && userAgent.indexOf("360 Aphone") == -1) {
sel.addEventListener('change', function (e) {
var f = sel.files[0]; // get selected file (camera capture)
fr = new FileReader();
fr.onload = receivedData; // add onload event
fr.readAsDataURL(f); // get captured image as data URI
});
$('#imgtag').show();
$('.div_video').hide();
$('#snap').click(function () {
sel.click();
});
} //判断是否Safari浏览器
else {
AlertDialog.Alert('对不起,您的浏览器不支持拍照功能,请使用其他浏览器', '提示');
}
}
}, false);
}
catch (err) {
AlertDialog.Alert("", "对不起,您的浏览器不支持拍照功能,请使用其他浏览器", "");
//AlertDialog.Alert('对不起,您的浏览器不支持拍照功能,请使用其他浏览器', '提示');
}
});
// for iOS
// create file reader
function receivedData() {
// readAsDataURL is finished - add URI to IMG tag src
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var imgtag = document.getElementById('imgtag'); // get reference to img tag
imgtag.src = fr.result;
$('#cream_loading').toggle();
try {
setTimeout(function () {
context.drawImage(imgtag, 0, 0, 640, 480);
convertCanvasToImage();
}, 500);
}
catch (err) {
alert(err);
}
}
//帆布转换成图像并保存图片
function convertCanvasToImage(canvas) {
var image = new Image();
image.src = document.getElementById("canvas").toDataURL("image/png");
//alert(image.src);
//删除字符串前的提示信息“data:image/png;base64”
var b64 = image.src.substring(22);
var myDate = new Date();
var filename = myDate.getTime();
$.post("/Article/SavePhoto", { data: b64, name: filename }, function (result) {
if (result.success) {
$('#cream_loading').toggle();
window.location.href = "/yourreenex?photo=" + result.photo;
}
});
return image;
}
</script>
<div id="main" class="masthead">
<div id="face_scan_camera" class="container blackbg" style="height: 792px;">
<div style="width: 1400px; margin: 0 auto;">
<video id="video" width="1400" height="790" autoplay="autoplay" style="margin: 0 auto; position: relative; z-index: 100;"></video>
</div>
<div class="camera-mask"></div>
<div class="camera-area" style="width: 450px; height: 350px; background: url(/images/lifescan/scan_kuang1.png) no-repeat; z-index: 102; top: 560px; left: 780px;">
<img src="/images/lifescan/scan_kuang1.png" />
<div class="scan-area" style="height: 585px; width: 580px; display: none;">
<canvas id="canvas" width="1054" height="790" style="display: inline-block; margin: 0 auto; position: relative; left: 13px; top: 70px; z-index: 100;"></canvas>
</div>
<a id="snap">
<img src="/images/lifescan/camera_btn.png" /></a>
</div>
</div>
<div id="cream_loading" style="display: none; position: absolute; margin: -62px 0 0 -62px; top: 50%; left: 50%; height: 124px; width: 124px; z-index: 2001;">
<img src="/Images/cream_loading.gif" />
</div>
</div>
这个方案里面调用摄像头比较复杂,在做的过程中发现一个投机取巧的办法。
方案二:
直接在页面上面放一个上传控件,在手机端的某些浏览器中(如 qq 浏览器,谷歌,android 自带的等)也能打开摄像头!luck!
于是开搞!
<script type="text/javascript" src="scripts/jquery-1.11.1.min.js"></script>
<script type="text/javascript">
var imgWidth = 0;
$(function () {
imgWidth = $("#divMain").width();
})
function setImagePreview() {
var preview, img_txt, localImag, file_head = document.getElementById("<%=fuRQCodeFile.ClientID%>"), picture = file_head.value;
//var preview, img_txt, localImag, file_head = document.getElementById("file_head"), picture = file_head.value;
if (!picture.match(/.jpg|.gif|.png|.bmp/i))
return alert("您上传的图片格式不正确,请重新选择!"), !1;
if (preview = document.getElementById("preview"), file_head.files && file_head.files[0]) preview.style.display = "block",
preview.style.width = imgWidth + "px",
preview.src = window.navigator.userAgent.indexOf("Chrome") >= 1 || window.navigator.userAgent.indexOf("Safari") >= 1 ? window.webkitURL.createObjectURL(file_head.files[0]) : window.URL.createObjectURL(file_head.files[0]);
$("#<%=btnUpload.ClientID%>").click();
//else {
// file_head.select(),
// file_head.blur(),
// img_txt = document.selection.createRange().text,
// localImag = document.getElementById("localImag"),
// //localImag.style.width = "63px",
// //localImag.style.height = "63px";
// localImag.style.width = imgWidth + "px";
// try {
// localImag.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)",
// localImag.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = img_txt
// } catch (f) {
// return alert("您上传的图片格式不正确,请重新选择!"),
// !1
// }
// preview.style.display = "none",
// document.selection.empty();
//}
//return document.getElementById("DivUp").style.display = "block",
//!0
}
</script>
<div>
<div>
<asp:Label ID="LblContent" runat="server"></asp:Label>
<div>
<asp:FileUpload ID="fuRQCodeFile" οnchange="javascript:setImagePreview();" runat="server" />
<%--<input type="file" name="file_head" id="file_head" οnchange="javascript:setImagePreview();" />--%>
</div>
</div>
<div id="localImag">
<img id="preview" width="-1" height="-1" style="display: none" />
</div>
<div style="display: none;">
<asp:Button ID="btnUpload" Text="识别二维码" OnClick="btnUpload_Click" runat="server" Style="display: none;" />
</div>
</div>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using ZXing;
namespace QR_Code
{
public partial class QRCodeTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
/// <summary>
/// 将大图转换成小图(图片太大会导致解析异常)
/// </summary>
/// <param name="bm"></param>
protected void ConverToSmallImg(ref Bitmap bm)
{
Bitmap bitmap = (Bitmap)Bitmap.FromStream(fuRQCodeFile.FileContent, false);
System.Drawing.Image img = System.Drawing.Image.FromStream(fuRQCodeFile.FileContent);
int sHeight, sWidth = 200;
int temp = img.Width / sWidth;
sHeight = img.Height / temp;
bm = new Bitmap(sWidth, sHeight);
Graphics gph = Graphics.FromImage(bm);
gph.DrawImage(img, 0, 0, sWidth, sHeight);
}
protected void btnUpload_Click(object sender, EventArgs e)
{
try
{
Bitmap bitMap = null;
ConverToSmallImg(ref bitMap);
BarcodeReader reader = new BarcodeReader();
Result result = reader.Decode(bitMap);
LblContent.Text = result.Text;
}
catch (Exception ex)
{
LblContent.Text = "出现异常" + ex.Message;
}
}
}
}
这样就能打开摄像头,拍一张相片,然后放到 fileupload 上面,通过 jquery 模拟点击上传,然后后台通过 zxing 识别。
需要注意的是,现在 android 手机拍出来的相片非常大!会出现异常,所以把图片等比缩放,将大大提升识别成功率。
附:
zxing GitHub下载地址:https://github.com/zxing/zxing
选择 C# 版本的下载就行