mirror of
https://github.com/Merricx/qrazybox.git
synced 2025-02-16 06:52:58 +01:00
wip: support more QR code versions
This commit is contained in:
parent
12df65b9d6
commit
6fb5b55863
5 changed files with 345 additions and 5 deletions
61
finder-example.html
Normal file
61
finder-example.html
Normal file
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>QR Code Finder Example</title>
|
||||
<meta charset="utf-8" />
|
||||
<style>
|
||||
#links > a {
|
||||
display: inline-block;
|
||||
margin: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="links"></div>
|
||||
<canvas id="canvas-1" width="800" height="800"></canvas>
|
||||
<script src="js/qr.js"></script>
|
||||
<script type="text/javascript">
|
||||
let links = document.getElementById('links');
|
||||
|
||||
for(let i=0; i<20; i++) {
|
||||
let link = document.createElement('a');
|
||||
link.href = "#" + (i + 1);
|
||||
link.text = i+1;
|
||||
links.appendChild(link);
|
||||
}
|
||||
|
||||
let canvas = document.getElementById("canvas-1");
|
||||
let ctx = canvas.getContext("2d");
|
||||
|
||||
window.addEventListener("hashchange", refreshQR);
|
||||
|
||||
function refreshQR() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
let fragment = window.location.hash.substr(1);
|
||||
let qrCodeVersion = 1;
|
||||
if (fragment != "") {
|
||||
qrCodeVersion = fragment * 1;
|
||||
}
|
||||
|
||||
let wsize = 10;
|
||||
let hsize = 10;
|
||||
let qrTemplate = generate_qr(qrCodeVersion);
|
||||
|
||||
for (let i = 0; i < qrTemplate.length; i++) {
|
||||
for (let j = 0; j < qrTemplate[0].length; j++) {
|
||||
// Drawing (i, j)
|
||||
let v = qrTemplate[i][j];
|
||||
if (v == -1) {
|
||||
v = 2;
|
||||
}
|
||||
let colorArr = ["white", "black", "grey"];
|
||||
let color = colorArr[v];
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillRect(i * wsize, j * hsize, wsize, hsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
refreshQR();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
61
index2.html
Normal file
61
index2.html
Normal file
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>QR Code Display</title>
|
||||
<meta charset="utf-8" />
|
||||
<style>
|
||||
#links > a {
|
||||
display: inline-block;
|
||||
margin: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="links"></div>
|
||||
<canvas id="canvas-1" width="800" height="800"></canvas>
|
||||
<script src="js/table.js"></script>
|
||||
<script type="text/javascript">
|
||||
let links = document.getElementById('links');
|
||||
|
||||
for(let i=0; i<20; i++) {
|
||||
let link = document.createElement('a');
|
||||
link.href = "#" + (i + 1);
|
||||
link.text = i+1;
|
||||
links.appendChild(link);
|
||||
}
|
||||
|
||||
let canvas = document.getElementById("canvas-1");
|
||||
let ctx = canvas.getContext("2d");
|
||||
|
||||
window.addEventListener("hashchange", refreshQR);
|
||||
|
||||
function refreshQR() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
let fragment = window.location.hash.substr(1);
|
||||
let qrCodeVersion = 1;
|
||||
if (fragment != "") {
|
||||
qrCodeVersion = fragment * 1;
|
||||
}
|
||||
|
||||
let wsize = 10;
|
||||
let hsize = 10;
|
||||
let qrTemplate = qr_templates[qrCodeVersion - 1];
|
||||
|
||||
for (let i = 0; i < qrTemplate.length; i++) {
|
||||
for (let j = 0; j < qrTemplate[0].length; j++) {
|
||||
// Drawing (i, j)
|
||||
let v = qrTemplate[i][j];
|
||||
if (v == -1) {
|
||||
v = 2;
|
||||
}
|
||||
let colorArr = ["white", "black", "grey", "red"];
|
||||
let color = colorArr[v];
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillRect(i * wsize, j * hsize, wsize, hsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
refreshQR();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
11
js/main.js
11
js/main.js
|
@ -6,7 +6,7 @@
|
|||
****************************************
|
||||
*/
|
||||
|
||||
var APP_VERSION = '0.3.3';
|
||||
var APP_VERSION = '0.4.0';
|
||||
|
||||
var qr_version = 1; //Current QR version (1-9)
|
||||
var qr_pixel_size = 10; //Current view size of QR code (pixel per module)
|
||||
|
@ -33,6 +33,9 @@ var is_data_module = []; //Store data that separate between data module a
|
|||
var history_array = []; //Store history information and its qr_array data
|
||||
var active_history = -1; //Current active history
|
||||
|
||||
const maxSupportedSize = 100;
|
||||
const maxVersion = 50;
|
||||
|
||||
/***
|
||||
*
|
||||
* generate QR table based on qr_array
|
||||
|
@ -571,7 +574,7 @@ function importFromImage(src, cb){
|
|||
|
||||
var qrArray = qRCodeMatrix.bits.bits;
|
||||
var size = qRCodeMatrix.bits.width;
|
||||
if(size > 53){
|
||||
if(size > maxSupportedSize){
|
||||
alert("QR version is unsupported");
|
||||
return;
|
||||
}
|
||||
|
@ -1462,7 +1465,7 @@ $(document).ready(function(){
|
|||
$("#btn-version-plus").click(function(){
|
||||
if(changed_state){
|
||||
if(confirm("Are you sure want to proceed?\nYour unsaved progress will be lost!")){
|
||||
if(qr_version != 9){
|
||||
if(qr_version != maxVersion){
|
||||
qr_version += 1;
|
||||
qr_size = 17+(qr_version*4);
|
||||
$("#qr-version").val(qr_size+"x"+qr_size+" (ver. "+qr_version+")");
|
||||
|
@ -1470,7 +1473,7 @@ $(document).ready(function(){
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if(qr_version != 9){
|
||||
if(qr_version != maxVersion){
|
||||
qr_version += 1;
|
||||
qr_size = 17+(qr_version*4);
|
||||
$("#qr-version").val(qr_size+"x"+qr_size+" (ver. "+qr_version+")");
|
||||
|
|
197
js/qr.js
Normal file
197
js/qr.js
Normal file
|
@ -0,0 +1,197 @@
|
|||
const WHITE_COLOR = 0;
|
||||
const BLACK_COLOR = 1;
|
||||
const RED_COLOR = 3;
|
||||
const GREY_COLOR = -1;
|
||||
|
||||
/*
|
||||
A finder is defined by 3 squares:
|
||||
- A black 7x7 square
|
||||
- A white 5x5 square
|
||||
- A black 3x3 square
|
||||
|
||||
Padding is denoted by a 9x9 square surrounding the element
|
||||
and being cropped on its corners.
|
||||
|
||||
x and y denote the (x,y) coordinate of the 7x7 square, taken
|
||||
at the top left corner
|
||||
*/
|
||||
|
||||
function draw_square(t, x, y, size, color){
|
||||
for(let i=x; i<x+size; i++){
|
||||
for(let j=y; j<y+size; j++){
|
||||
if(i >= t.length || i < 0){
|
||||
continue
|
||||
}
|
||||
if(j >= t.length || j < 0) {
|
||||
continue
|
||||
}
|
||||
t[i][j] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generate_finder_separator(t, x, y) {
|
||||
return draw_square(t, x - 1, y - 1, 9, WHITE_COLOR);
|
||||
}
|
||||
|
||||
function generate_finder(t, x, y){
|
||||
generate_finder_separator(t, x, y);
|
||||
draw_square(t, x, y, 7, BLACK_COLOR);
|
||||
draw_square(t, x + 1, y + 1, 5, WHITE_COLOR);
|
||||
draw_square(t, x + 2, y + 2, 3, BLACK_COLOR);
|
||||
}
|
||||
|
||||
/*
|
||||
The timing patterns is a pattern of black / white squares (1x1) that
|
||||
begin with a black one and move either horizontally or vertically,
|
||||
connecting the finders separators.
|
||||
*/
|
||||
function generate_timing_pattern_v(t, xStart, yStart, yEnd){
|
||||
// Start with black
|
||||
let current = BLACK_COLOR;
|
||||
for(let j=yStart; j<=yEnd; j++){
|
||||
t[xStart][j] = current;
|
||||
current = (current == BLACK_COLOR ? WHITE_COLOR : BLACK_COLOR)
|
||||
}
|
||||
}
|
||||
|
||||
function generate_timing_pattern_h(t, xStart, yStart, xEnd){
|
||||
// Start with black
|
||||
let current = BLACK_COLOR;
|
||||
for(let i=xStart; i<=xEnd; i++){
|
||||
t[i][yStart] = current;
|
||||
current = (current == BLACK_COLOR ? WHITE_COLOR : BLACK_COLOR)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let versions = [];
|
||||
for(let i=0;i<40;i++){
|
||||
versions.push(
|
||||
[21 + i*4, 21 + i*4]
|
||||
)
|
||||
}
|
||||
|
||||
let alignment_lookup = [
|
||||
[],
|
||||
[6, 18],
|
||||
[6, 22],
|
||||
[6, 26],
|
||||
[6, 30],
|
||||
[6, 34],
|
||||
[6, 22, 38],
|
||||
[6, 24, 42],
|
||||
[6, 26, 46],
|
||||
[6, 28, 50],
|
||||
[6, 30, 54],
|
||||
[6, 32, 58],
|
||||
[6, 34, 62],
|
||||
[6, 26, 46, 66],
|
||||
[6, 26, 48, 70],
|
||||
[6, 26, 50, 74],
|
||||
[6, 30, 54, 78],
|
||||
[6, 30, 56, 82],
|
||||
[6, 30, 58, 86],
|
||||
[6, 34, 62, 90],
|
||||
[6, 28, 50, 72, 94],
|
||||
[6, 26, 50, 74, 98],
|
||||
[6, 30, 54, 78, 102],
|
||||
[6, 28, 54, 80, 106],
|
||||
[6, 32, 58, 84, 110],
|
||||
[6, 30, 58, 86, 114],
|
||||
[6, 34, 62, 90, 118],
|
||||
[6, 26, 50, 74, 98, 122],
|
||||
[6, 30, 54, 78, 102, 126],
|
||||
[6, 26, 52, 78, 104, 130],
|
||||
[6, 30, 56, 82, 108, 134],
|
||||
[6, 34, 60, 86, 112, 138],
|
||||
[6, 30, 58, 86, 114, 142],
|
||||
[6, 34, 62, 90, 118, 146],
|
||||
[6, 30, 54, 78, 102, 126, 150],
|
||||
[6, 24, 50, 76, 102, 128, 154],
|
||||
[6, 28, 54, 80, 106, 132, 158],
|
||||
[6, 32, 58, 84, 110, 136, 162],
|
||||
[6, 26, 54, 82, 110, 138, 166],
|
||||
[6, 30, 58, 86, 114, 142, 170]
|
||||
];
|
||||
|
||||
/*
|
||||
Alignment patterns are boxes sized 5x5 that are
|
||||
formed as follows:
|
||||
|
||||
- Outer 5x5 black square
|
||||
- Inner 3x3 white square
|
||||
- Inner-most 1x1 black square
|
||||
|
||||
The coordinates from alignment_lookup refer to the center
|
||||
of the alignment pattern (the 1x1 square).
|
||||
*/
|
||||
|
||||
function add_alignment_patterns(t, index){
|
||||
let alignment = alignment_lookup[index];
|
||||
if(alignment.length == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
let alignment_locs = [];
|
||||
|
||||
for(let i=0; i<alignment.length; i++){
|
||||
for(let j=0; j<alignment.length; j++){
|
||||
alignment_locs.push([alignment[i], alignment[j]]);
|
||||
}
|
||||
}
|
||||
|
||||
for(let align of alignment_locs){
|
||||
let [x, y] = [align[0], align[1]];
|
||||
|
||||
let [l_x, r_x] = [x-2, x+2];
|
||||
let [t_y, b_y] = [y-2, y+2];
|
||||
|
||||
if(r_x > t.length - 8 && t_y < 8) {
|
||||
continue
|
||||
}
|
||||
|
||||
if(l_x < 8 && t_y < 8) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(l_x < 8 && b_y > t.length - 8){
|
||||
continue
|
||||
}
|
||||
|
||||
draw_square(t, x-2, y-2, 5, BLACK_COLOR);
|
||||
draw_square(t, x-1, y-1, 3, WHITE_COLOR);
|
||||
draw_square(t, x, y, 1, BLACK_COLOR);
|
||||
|
||||
|
||||
}
|
||||
console.log(alignment_locs);
|
||||
}
|
||||
|
||||
function generate_qr(version){
|
||||
console.log(`Generating ${version}`)
|
||||
let t = [];
|
||||
let sizes = versions[version-1];
|
||||
let x_max = sizes[0];
|
||||
let y_max = sizes[1];
|
||||
|
||||
for(let i = 0; i<x_max; i++){
|
||||
let arr = [];
|
||||
for(let j=0; j<y_max; j++){
|
||||
arr.push(GREY_COLOR);
|
||||
}
|
||||
t.push(arr);
|
||||
}
|
||||
|
||||
// Add finder
|
||||
generate_finder(t, 0, 0);
|
||||
generate_finder(t, x_max - 7, 0);
|
||||
generate_finder(t, 0, y_max - 7);
|
||||
|
||||
generate_timing_pattern_v(t, 6, 8, y_max-9);
|
||||
generate_timing_pattern_h(t, 8, 6, x_max-9);
|
||||
|
||||
add_alignment_patterns(t, version-1);
|
||||
|
||||
return t;
|
||||
}
|
20
js/table.js
20
js/table.js
|
@ -56,7 +56,25 @@ var alignment_pattern_array = [
|
|||
[6, 34],
|
||||
[6, 22, 38],
|
||||
[6, 24, 42],
|
||||
[6, 26, 46]
|
||||
[6, 26, 46],
|
||||
[6, 28, 50],
|
||||
[6, 30, 54],
|
||||
[6, 32, 58],
|
||||
[6, 34, 62],
|
||||
[6, 26, 46, 66],
|
||||
[6, 26, 36, 66],
|
||||
[6, 26, 48, 70],
|
||||
[6, 26, 50, 74],
|
||||
[6, 30, 54, 78],
|
||||
[6, 30, 56, 82],
|
||||
[6, 30, 58, 86],
|
||||
[6, 34, 62, 90],
|
||||
[6, 28, 50, 72, 94],
|
||||
[6, 26, 50, 74, 98],
|
||||
[6, 30, 54, 78, 102],
|
||||
[6, 28, 54, 80, 106],
|
||||
[6, 32, 58, 84, 110],
|
||||
[6, 30, 58, 86, 114]
|
||||
];
|
||||
|
||||
var format_information_bits_raw = {
|
||||
|
|
Loading…
Reference in a new issue