提交 3f535514 编写于 作者: MuGuiLin's avatar MuGuiLin 🏡

add htmlqrcode

上级 0365839d
.h1{
* {
margin : 0;
padding: 0;
}
.h2 {
text-align: center;
}
.reader {
text-align: center;
font-size: 16px;
}
.canvas {
display : none;
box-sizing: border-box;
position : fixed;
top : 0;
right : 0;
bottom : 0;
left : 0;
width : 100vw;
height : 100vh;
}
.reader .sweep {
position : relative;
margin : 20px;
padding : 12px;
width : 300px;
font-size : 18px;
cursor : pointer;
color : white;
background: #42b983;
border : 1px solid #42b983;
overflow : hidden;
}
.reader .sweep input {
position : absolute;
font-size: 100px;
opacity : 0;
}
.reader .imgurl {
margin : 20px;
text-align: center;
}
.reader .imgurl img {
margin : 20px;
padding : 10px;
border : 1px solid gray;
border-radius: 8px;
width : 280px;
height : 260px;
}
.reader .result {
box-sizing : border-box;
padding : 10px;
border : 1px solid gray;
border-radius: 8px;
font-size : 16px;
}
\ No newline at end of file
......@@ -10,10 +10,47 @@
</head>
<body>
<h1 class="h1">纯前端 JS :二维码:生成、扫描、识别 (HTML版)</h1>
<h2 class="h2">纯前端 JS :二维码:生成、扫描、识别 (HTML版)</h2>
<hr />
<main class="reader">
<button class="sweep" onclick="sweep()">扫一扫</button>
<button class="sweep">
<input type="file" id="file" onchange="upload()" />从相册选择
</button>
<div class="imgurl">
<img id="imgurl" src="https://raw.githubusercontent.com/MuGuiLin/QRCode/master/VueQRCode/src/assets/github.com.png" alt="当前识别的二维码" />
</div>
<textarea class="result" id="result" cols="32" rows="6" placeholder="二维码识别结果!"></textarea>
</main>
<canvas class="canvas" id="canvas"></canvas>
<script src="./js/jimp.js"></script>
<script src="./js/jsqr.js"></script>
<script src="./js/base.js"></script>
<script>
const QrCode = new QrCodeRecognition({
id: '#canvas',
seuccess: function (res) {
document.querySelector('#result').value = res.data;
},
error: function (err) {
document.querySelector('#result').value = err;
console.error(err);
}
});
function sweep() {
QrCode.init();
}
function upload() {
QrCode.upload();
}
</script>
</body>
</html>
\ No newline at end of file
class QrCodeRecognition {
constructor(opts = {}) {
this.timer = null;
this.result = "";
this.isAnimation = true;
this.lineWidth = opts.borderWidth || 3;
this.strokeStyle = opts.lineColor || 'red';
this.audio = new Audio(opts.audio || './js/tone.mp3');
this.video = document.createElement('video');
this.cvsele = document.querySelector(opts.id);
this.canvas = this.cvsele.getContext('2d');
this.seuccess = opts.seuccess || Function;
this.error = opts.error || Function;
};
draw(begin, end) {
this.canvas.beginPath();
this.canvas.moveTo(begin.x, begin.y);
this.canvas.lineTo(end.x, end.y);
this.canvas.lineWidth = this.lineWidth;
this.canvas.strokeStyle = this.strokeStyle;
this.canvas.stroke();
};
sweep() {
if (this.video.readyState === this.video.HAVE_ENOUGH_DATA) {
const { videoWidth, videoHeight } = this.video;
this.cvsele.width = videoWidth;
this.cvsele.height = videoHeight;
this.canvas.drawImage(this.video, 0, 0, videoWidth, videoHeight);
try {
const img = this.canvas.getImageData(0, 0, videoWidth, videoHeight);
document.querySelector('#imgurl').src = img;
const obj = jsQR(img.data, img.width, img.height, { inversionAttempts: 'dontInvert' });
if (obj) {
const loc = obj.location;
this.draw(loc.topLeftCorner, loc.topRightCorner);
this.draw(loc.topRightCorner, loc.bottomRightCorner);
this.draw(loc.bottomRightCorner, loc.bottomLeftCorner);
this.draw(loc.bottomLeftCorner, loc.topLeftCorner);
if (this.result != obj.data) {
this.audio.play();
this.seuccess(obj);
this.isAnimation = false;
cancelAnimationFrame(this.timer);
console.info("识别结果:", obj.data);
setTimeout(() => {
this.cvsele.style.display = "none";
}, 1000);
}
} else {
this.error("识别失败,请检查二维码是否正确!");
console.error("识别失败,请检查二维码是否正确!");
}
} catch (err) {
this.error(err);
console.error("识别失败,请检查二维码是否正确!", err);
};
};
if (this.isAnimation) {
this.timer = requestAnimationFrame(() => {
this.sweep();
});
}
};
upload() {
const ele = document.querySelector('#file');
const file = ele.files[0];
const createObjectURL = window.createObjectURL || window.URL.createObjectURL || window.webkitURL.createObjectUR;
document.querySelector('#result').value = '';
const fReader = new FileReader();
fReader.readAsDataURL(file); // Base64 8Bit字节码
// fReader.readAsBinaryString(file); // Binary 原始二进制
// fReader.readAsArrayBuffer(file); // ArrayBuffer 文件流
fReader.onload = (e) => {
document.querySelector('#imgurl').src = e.target.result || createObjectURL(file);
e.target.result && Jimp.read(e.target.result).then(async (res) => {
const { data, width, height } = res.bitmap;
try {
const resolve = await jsQR(data, width, height);
this.audio.play();
this.seuccess(resolve);
console.info("识别结果:", resolve.data);
} catch (err) {
this.error("识别失败,请检查二维码是否正确!");
console.error("识别失败,请检查二维码是否正确!", err);
} finally {
console.info("读取到的文件:", res);
}
}).catch((err) => {
this.error("文件读取错误:", err);
console.error("文件读取错误:", err);
});
};
};
init() {
this.isAnimation = true;
this.cvsele.style.display = "block";
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
if (navigator.mediaDevices) {
navigator.mediaDevices.getUserMedia({
video: { facingMode: "environment" }
}).then(stream => {
this.video.srcObject = stream;
this.video.setAttribute('playsinline', true);
this.video.setAttribute('webkit-playsinline', true);
this.video.addEventListener('loadedmetadata', () => {
this.video.play();
this.sweep();
});
}).catch(error => {
console.error(error.name + "" + error.message + "" + error.constraint);
});
} else if (navigator.getUserMedia) {
navigator.getUserMedia({
video: { facingMode: "environment" }
}, (stream) => {
this.video.srcObject = stream;
this.video.setAttribute('playsinline', true);
this.video.setAttribute('webkit-playsinline', true);
this.video.addEventListener('loadedmetadata', () => {
this.video.play();
this.sweep();
});
}, (error) => {
console.error(error.name + "" + error.message + "" + error.constraint);
});
} else {
if (navigator.userAgent.toLowerCase().match(/chrome/) && location.origin.indexOf('https://') < 0) {
console.error('获取浏览器录音功能,因安全性问题,需要在localhost 或 127.0.0.1 或 https 下才能获取权限!');
} else {
alert('对不起:未识别到扫描设备!');
}
};
}
};
\ No newline at end of file
此差异已折叠。
此差异已折叠。
.reader{font-size:16px}.reader .sweep{position:relative;margin:20px;padding:12px;width:300px;font-size:18px;cursor:pointer;color:#fff;background:#42b983;border:1px solid #42b983;overflow:hidden}.reader .sweep input{position:absolute;font-size:100px;opacity:0}.reader .imgurl{margin:20px;text-align:center}.reader .imgurl img{margin:20px;width:280px;height:260px}.reader .imgurl img,.reader .result{padding:10px;border:1px solid grey;border-radius:8px}.reader .result{box-sizing:border-box;font-size:16px}.reader .canvas{display:none;box-sizing:border-box;position:fixed;top:0;right:0;bottom:0;left:0;width:100vw;height:100vh}
\ No newline at end of file
#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50}#nav{padding:30px;font-size:18px}#nav a{padding:10px;font-weight:700;color:#2c3e50}#nav a.router-link-exact-active{color:#42b983}.qrcode .form{margin:30px}.qrcode .form input{padding:0 10px;width:360px;height:46px;font-size:18px}.qrcode .form button{width:150px;height:50px;font-size:18px;vertical-align:top;background:#42b983;border:1px solid #767676;border-left:none}.qrcode .form button a{color:#fff;text-decoration:none}.qrcode .code{margin:auto;padding:8px;width:360px;height:360px;border-radius:8px;border:2px solid grey}
\ No newline at end of file
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>qrcode</title><link href="css/about.895473a2.css" rel="prefetch"><link href="js/about.a463a6c0.js" rel="prefetch"><link href="css/app.b3880e9e.css" rel="preload" as="style"><link href="js/app.23d60dfc.js" rel="preload" as="script"><link href="js/chunk-vendors.e9de5715.js" rel="preload" as="script"><link href="css/app.b3880e9e.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but qrcode doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.e9de5715.js"></script><script src="js/app.23d60dfc.js"></script></body></html>
\ No newline at end of file
此差异已折叠。
此差异已折叠。
(function(e){function t(t){for(var o,n,c=t[0],i=t[1],l=t[2],s=0,d=[];s<c.length;s++)n=c[s],Object.prototype.hasOwnProperty.call(a,n)&&a[n]&&d.push(a[n][0]),a[n]=0;for(o in i)Object.prototype.hasOwnProperty.call(i,o)&&(e[o]=i[o]);f&&f(t);while(d.length)d.shift()();return u.push.apply(u,l||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],o=!0,n=1;n<r.length;n++){var c=r[n];0!==a[c]&&(o=!1)}o&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var o={},n={app:0},a={app:0},u=[];function c(e){return i.p+"js/"+({about:"about"}[e]||e)+"."+{about:"a463a6c0"}[e]+".js"}function i(t){if(o[t])return o[t].exports;var r=o[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r={about:1};n[e]?t.push(n[e]):0!==n[e]&&r[e]&&t.push(n[e]=new Promise((function(t,r){for(var o="css/"+({about:"about"}[e]||e)+"."+{about:"895473a2"}[e]+".css",a=i.p+o,u=document.getElementsByTagName("link"),c=0;c<u.length;c++){var l=u[c],s=l.getAttribute("data-href")||l.getAttribute("href");if("stylesheet"===l.rel&&(s===o||s===a))return t()}var d=document.getElementsByTagName("style");for(c=0;c<d.length;c++){l=d[c],s=l.getAttribute("data-href");if(s===o||s===a)return t()}var f=document.createElement("link");f.rel="stylesheet",f.type="text/css",f.onload=t,f.onerror=function(t){var o=t&&t.target&&t.target.src||a,u=new Error("Loading CSS chunk "+e+" failed.\n("+o+")");u.code="CSS_CHUNK_LOAD_FAILED",u.request=o,delete n[e],f.parentNode.removeChild(f),r(u)},f.href=a;var p=document.getElementsByTagName("head")[0];p.appendChild(f)})).then((function(){n[e]=0})));var o=a[e];if(0!==o)if(o)t.push(o[2]);else{var u=new Promise((function(t,r){o=a[e]=[t,r]}));t.push(o[2]=u);var l,s=document.createElement("script");s.charset="utf-8",s.timeout=120,i.nc&&s.setAttribute("nonce",i.nc),s.src=c(e);var d=new Error;l=function(t){s.onerror=s.onload=null,clearTimeout(f);var r=a[e];if(0!==r){if(r){var o=t&&("load"===t.type?"missing":t.type),n=t&&t.target&&t.target.src;d.message="Loading chunk "+e+" failed.\n("+o+": "+n+")",d.name="ChunkLoadError",d.type=o,d.request=n,r[1](d)}a[e]=void 0}};var f=setTimeout((function(){l({type:"timeout",target:s})}),12e4);s.onerror=s.onload=l,document.head.appendChild(s)}return Promise.all(t)},i.m=e,i.c=o,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)i.d(r,o,function(t){return e[t]}.bind(null,o));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i.oe=function(e){throw console.error(e),e};var l=window["webpackJsonp"]=window["webpackJsonp"]||[],s=l.push.bind(l);l.push=t,l=l.slice();for(var d=0;d<l.length;d++)t(l[d]);var f=s;u.push([0,"chunk-vendors"]),r()})({0:function(e,t,r){e.exports=r("56d7")},2395:function(e,t,r){},"520a":function(e,t,r){},"56d7":function(e,t,r){"use strict";r.r(t);r("e623"),r("e379"),r("5dc8"),r("37e1");var o=r("2b0e"),n=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{attrs:{id:"app"}},[r("div",{attrs:{id:"nav"}},[r("router-link",{attrs:{to:"/"}},[e._v("二维码生成")]),e._v(" | "),r("router-link",{attrs:{to:"/reader"}},[e._v("二维码识别")])],1),r("router-view")],1)},a=[],u=(r("7c55"),r("2877")),c={},i=Object(u["a"])(c,n,a,!1,null,null,null),l=i.exports,s=(r("d3b7"),r("3ca3"),r("ddb0"),r("8c4f")),d=function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("main",{staticClass:"qrcode"},[r("h1",[e._v("二维码 生成、渲染!(Vue.js版)")]),r("hr"),r("div",{staticClass:"form"},[r("input",{directives:[{name:"model",rawName:"v-model",value:e.text,expression:"text"}],attrs:{type:"text",placeholder:"请在这里输入要生成的内容!"},domProps:{value:e.text},on:{input:function(t){t.target.composing||(e.text=t.target.value)}}}),r("button",[r("a",{attrs:{href:e.href,target:"_blank",download:"下载的二维码",rel:"noopener noreferrer"}},[e._v(" 下载二维码")])])]),r("div",{ref:"code",staticClass:"code"},[r("vue-qr",{attrs:{qid:"qrid",text:e.text,size:e.size,bgSrc:e.bgSrc,logoSrc:e.logoSrc,callback:e.callBack,logoScale:e.logoScale,colorDark:e.colorDark,colorLight:e.colorLight,backgroundColor:e.backgroundColor}})],1)])},f=[],p=r("658f"),h=r.n(p),g={name:"Qrcode",components:{VueQr:h.a},data:function(){return{href:"",text:"https://github.com/MuGuiLin",size:360,bgSrc:"",logoSrc:"https://raw.githubusercontent.com/MuGuiLin/QRCode/master/VueQRCode/src/assets/logo.png",margin:0,colorDark:"blue",colorLight:"#42B983",backgroundColor:"#EEE",logoScale:.15,dotScale:.35}},methods:{callBack:function(e,t){this.href=e,console.log(e,t)}}},m=g,v=(r("7076"),Object(u["a"])(m,d,f,!1,null,null,null)),b=v.exports;o["a"].use(s["a"]);var y=[{path:"/",name:"Qrcode",component:b},{path:"/reader",name:"Reader",component:function(){return r.e("about").then(r.bind(null,"968f"))}}],w=new s["a"]({mode:"history",base:"",routes:y}),k=w,S=r("2f62");o["a"].use(S["a"]);var _=new S["a"].Store({state:{},mutations:{},actions:{},modules:{}});o["a"].config.productionTip=!1,new o["a"]({router:k,store:_,render:function(e){return e(l)}}).$mount("#app")},7076:function(e,t,r){"use strict";r("520a")},"7c55":function(e,t,r){"use strict";r("2395")}});
//# sourceMappingURL=app.23d60dfc.js.map
\ No newline at end of file
此差异已折叠。
因为 它太大了无法显示 source diff 。你可以改为 查看blob
此差异已折叠。
VueQRCode/src/assets/qrcode.png

32.6 KB | W: | H:

VueQRCode/src/assets/qrcode.png

33.5 KB | W: | H:

VueQRCode/src/assets/qrcode.png
VueQRCode/src/assets/qrcode.png
VueQRCode/src/assets/qrcode.png
VueQRCode/src/assets/qrcode.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -3,10 +3,11 @@
<h1>二维码 识别、读取、解码!(Vue.js版)</h1>
<hr />
<button class="sweep" @click="media()">扫一扫</button>
<button class="sweep">
<input type="file" @change="upload($event)" />
扫一扫
<input type="file" @change="upload($event)" />从相册选择
</button>
<div class="imgurl">
<img :src="imgurl" alt="当前识别的二维码" />
<img :src="imgurl2" alt="当前识别的二维码" />
......@@ -19,11 +20,12 @@
v-model="result"
placeholder="二维码识别结果!"
></textarea>
<canvas class="canvas" ref="canvas"></canvas>
</main>
</template>
<script>
// https://www.npmjs.com/package/jsqr
// https://www.npmjs.com/package/jimp
import jsQR from "jsqr";
......@@ -33,12 +35,140 @@ export default {
name: "Reader",
data() {
return {
timer: null,
result: "https://github.com/MuGuiLin",
imgurl: "https://raw.githubusercontent.com/MuGuiLin/QRCode/master/VueQRCode/src/assets/github.com.png",
imgurl2: "https://raw.githubusercontent.com/MuGuiLin/QRCode/master/VueQRCode/src/assets/github.com.png",
imgurl:
"https://raw.githubusercontent.com/MuGuiLin/QRCode/master/VueQRCode/src/assets/github.com.png",
imgurl2:
"https://raw.githubusercontent.com/MuGuiLin/QRCode/master/VueQRCode/src/assets/github.com.png",
isAnimation: true,
audio: Object,
video: Object,
cvsele: Object,
canvas: Object,
};
},
mounted() {
this.audio = new Audio("../assets/tone.mp3");
this.video = document.createElement("video");
this.cvsele = this.$refs.canvas;
this.canvas = this.cvsele.getContext("2d");
},
methods: {
draw(begin, end) {
this.canvas.beginPath();
this.canvas.moveTo(begin.x, begin.y);
this.canvas.lineTo(end.x, end.y);
this.canvas.lineWidth = 3;
this.canvas.strokeStyle = "red";
this.canvas.stroke();
},
sweep() {
if (this.video.readyState === this.video.HAVE_ENOUGH_DATA) {
const { videoWidth, videoHeight } = this.video;
this.cvsele.width = videoWidth;
this.cvsele.height = videoHeight;
this.canvas.drawImage(this.video, 0, 0, videoWidth, videoHeight);
try {
const img = this.canvas.getImageData(0, 0, videoWidth, videoHeight);
this.imgurl = img;
const obj = jsQR(img.data, img.width, img.height, {
inversionAttempts: "dontInvert",
});
if (obj) {
const loc = obj.location;
this.draw(loc.topLeftCorner, loc.topRightCorner);
this.draw(loc.topRightCorner, loc.bottomRightCorner);
this.draw(loc.bottomRightCorner, loc.bottomLeftCorner);
this.draw(loc.bottomLeftCorner, loc.topLeftCorner);
if (this.result != obj.data) {
this.audio.play();
this.result = obj.data;
this.isAnimation = false;
cancelAnimationFrame(this.timer);
console.info("识别结果:", obj.data);
setTimeout(() => {
this.cvsele.style.display = "none";
}, 1000);
}
} else {
console.error("识别失败,请检查二维码是否正确!");
}
} catch (err) {
console.error("识别失败,请检查二维码是否正确!", err);
}
}
if (this.isAnimation) {
this.timer = requestAnimationFrame(() => {
this.sweep();
});
}
},
media() {
this.isAnimation = true;
this.cvsele.style.display = "block";
navigator.getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
if (navigator.mediaDevices) {
navigator.mediaDevices
.getUserMedia({
video: { facingMode: "environment" },
})
.then((stream) => {
this.video.srcObject = stream;
this.video.setAttribute("playsinline", true);
this.video.setAttribute("webkit-playsinline", true);
this.video.addEventListener("loadedmetadata", () => {
this.video.play();
this.sweep();
});
})
.catch((error) => {
console.error(
error.name + "" + error.message + "" + error.constraint
);
});
} else if (navigator.getUserMedia) {
navigator.getUserMedia(
{
video: { facingMode: "environment" },
},
(stream) => {
this.video.srcObject = stream;
this.video.setAttribute("playsinline", true);
this.video.setAttribute("webkit-playsinline", true);
this.video.addEventListener("loadedmetadata", () => {
this.video.play();
this.sweep();
});
},
(error) => {
console.error(
error.name + "" + error.message + "" + error.constraint
);
}
);
} else {
if (
navigator.userAgent.toLowerCase().match(/chrome/) &&
location.origin.indexOf("https://") < 0
) {
console.error(
"获取浏览器录音功能,因安全性问题,需要在localhost 或 127.0.0.1 或 https 下才能获取权限!"
);
} else {
alert("对不起:未识别到扫描设备!");
}
}
},
upload(e) {
const file = e.target.files[0];
const createObjectURL =
......@@ -54,24 +184,22 @@ export default {
// fReader.readAsArrayBuffer(file); // ArrayBuffer 文件流
fReader.onload = (e) => {
this.imgurl2 = e.target.result;
e.target.result &&
Jimp.read(e.target.result)
.then(async (res) => {
const { data, width, height } = res.bitmap;
try {
const resolve = await jsQR(data, width, height);
this.result = resolve.data;
console.info("识别结果:", resolve.data);
} catch (err) {
this.result = "识别失败,请检查二维码是否正确!";
console.error("识别失败,请检查二维码是否正确!", err);
} finally {
console.info("读取到的文件:", res);
}
})
.catch((err) => {
console.error("文件读取错误:", err);
});
e.target.result && Jimp.read(e.target.result).then(async (res) => {
const { data, width, height } = res.bitmap;
try {
const resolve = await jsQR(data, width, height);
this.result = resolve.data;
console.info("识别结果:", resolve.data);
} catch (err) {
this.result = "识别失败,请检查二维码是否正确!";
console.error("识别失败,请检查二维码是否正确!", err);
} finally {
console.info("读取到的文件:", res);
}
})
.catch((err) => {
console.error("文件读取错误:", err);
});
};
},
},
......@@ -117,5 +245,16 @@ export default {
border-radius: 8px;
font-size: 16px;
}
.canvas {
display: none;
box-sizing: border-box;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100vw;
height: 100vh;
}
}
</style>
\ No newline at end of file
module.exports = {
publicPath: './'
};
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册