Compare commits

...

2 Commits

Author SHA1 Message Date
Lars Jung 631df8abac Update. 5 years ago
Lars Jung bf58382a98 Update. 6 years ago

@ -12,7 +12,7 @@ insert_final_newline = true
trim_trailing_whitespace = true
[{package.json,.eslintrc,.babelrc,.travis.yml}]
[{*.json,*.yml}]
indent_size = 2

@ -1,5 +1,4 @@
/build/
/coverage/
/dist/
/vendor/
/node_modules/

@ -5,6 +5,9 @@
es6: true
node: true
parserOptions:
ecmaVersion: 2020
rules:
array-bracket-spacing: [2, never]
arrow-parens: [2, as-needed]

@ -3,14 +3,14 @@
[![license][license-img]][github] [![web][web-img]][web] [![github][github-img]][github]
jQuery plugin to dynamically generate QR codes. Uses [QR Code Generator][qrcode] (MIT).
There is a jQuery-free lib named [kjua][kjua] that works in all modern browsers
There is a newer lib named [kjua][kjua] that works in all modern browsers
with crisp codes on all devices.
## License
The MIT License (MIT)
Copyright (c) 2019 Lars Jung (https://larsjung.de)
Copyright (c) 2020 Lars Jung (https://larsjung.de)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -1,5 +1,6 @@
const {resolve, join} = require('path');
const {ghu, includeit, pug, jszip, mapfn, read, remove, webpack, uglify, wrap, write} = require('ghu');
const {ghu, pug, jszip, mapfn, read, remove, webpack, uglify, wrap, write} = require('ghu');
const overwrite = arg => write(arg, {overwrite: true});
const NAME = 'jquery-qrcode';
@ -14,58 +15,52 @@ ghu.before(runtime => {
runtime.pkg = Object.assign({}, require('./package.json'));
runtime.comment = `${runtime.pkg.name} v${runtime.pkg.version} - ${runtime.pkg.homepage}`;
runtime.commentJs = `/*! ${runtime.comment} */\n`;
console.log(runtime.comment);
});
ghu.task('clean', 'delete build folder', () => {
ghu.task('clean', () => {
return remove(`${BUILD}, ${DIST}`);
});
ghu.task('build:scripts', runtime => {
return read(`${SRC}/${NAME}.js`)
.then(webpack(webpack.cfg_umd(NAME, [SRC]), {showStats: false}))
.then(includeit())
.then(webpack(webpack.cfg_umd(NAME, [SRC])))
.then(wrap(runtime.commentJs))
.then(write(`${DIST}/${NAME}.js`, {overwrite: true}))
.then(write(`${BUILD}/${NAME}-${runtime.pkg.version}.js`, {overwrite: true}))
.then(overwrite(`${DIST}/${NAME}.js`))
.then(overwrite(`${BUILD}/${NAME}-${runtime.pkg.version}.js`))
.then(uglify())
.then(wrap(runtime.commentJs))
.then(write(`${DIST}/${NAME}.min.js`, {overwrite: true}))
.then(write(`${BUILD}/${NAME}-${runtime.pkg.version}.min.js`, {overwrite: true}));
.then(overwrite(`${DIST}/${NAME}.min.js`))
.then(overwrite(`${BUILD}/${NAME}-${runtime.pkg.version}.min.js`));
});
ghu.task('build:demo', runtime => {
ghu.task('build:other', runtime => {
return Promise.all([
read(`${ROOT}/*.md`)
.then(overwrite(mapfn.p(ROOT, BUILD))),
read(`${SRC}/demo/*.pug`)
.then(pug({pkg: runtime.pkg}))
.then(write(mapfn.p(SRC, BUILD).s('.pug', ''), {overwrite: true})),
.then(overwrite(mapfn.p(SRC, BUILD).s('.pug', ''))),
read(`${SRC}/demo/*.js`)
.then(webpack(webpack.cfg([SRC]), {showStats: false}))
.then(webpack(webpack.cfg([SRC])))
.then(uglify())
.then(wrap(runtime.commentJs))
.then(write(mapfn.p(SRC, BUILD), {overwrite: true})),
.then(overwrite(mapfn.p(SRC, BUILD))),
read(`${SRC}/demo/*, !**/*.pug, !**/*.js`)
.then(write(mapfn.p(SRC, BUILD), {overwrite: true})),
.then(overwrite(mapfn.p(SRC, BUILD))),
read(`${ROOT}/node_modules/jquery/dist/jquery.min.js`)
.then(write(`${BUILD}/demo/jquery.min.js`, {overwrite: true}))
]);
});
ghu.task('build:copy', () => {
return Promise.all([
read(`${ROOT}/*.md`)
.then(write(mapfn.p(ROOT, BUILD), {overwrite: true}))
.then(overwrite(`${BUILD}/demo/jquery.min.js`))
]);
});
ghu.task('build', ['build:scripts', 'build:demo', 'build:copy']);
ghu.task('build', ['build:scripts', 'build:other']);
ghu.task('zip', ['build'], runtime => {
return read(`${BUILD}/**/*`)
.then(jszip({dir: BUILD, level: 9}))
.then(write(`${BUILD}/${NAME}-${runtime.pkg.version}.zip`, {overwrite: true}));
.then(overwrite(`${BUILD}/${NAME}-${runtime.pkg.version}.zip`));
});
ghu.task('release', ['clean', 'zip']);

4865
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,15 +1,14 @@
{
"name": "jquery-qrcode",
"title": "jQuery.qrcode",
"version": "0.16.0",
"version": "0.18.0",
"description": "Generate QR codes dynamically.",
"homepage": "https://larsjung.de/jquery-qrcode/",
"bugs": "https://github.com/lrsjng/jquery-qrcode/issues",
"author": "Lars Jung <lrsjng@gmail.com> (https://larsjung.de)",
"license": "MIT",
"scripts": {
"lint": "eslint .",
"build": "node ghu.js release",
"build": "node ghu release",
"precommit": "npm run -s lint && npm run -s build"
},
"repository": {
@ -17,13 +16,11 @@
"url": "https://github.com/lrsjng/jquery-qrcode.git"
},
"devDependencies": {
"@babel/core": "7.4.3",
"@babel/preset-env": "7.4.3",
"eslint": "5.16.0",
"ghu": "0.17.0",
"jquery": "3.4.0"
},
"engines": {
"node": ">=8.0.0"
"@babel/core": "7.10.5",
"@babel/preset-env": "7.10.4",
"eslint": "7.5.0",
"ghu": "0.26.0",
"jquery": "3.5.1",
"qrcode-generator": "1.4.4"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

@ -2,12 +2,11 @@ doctype html
html(lang='en')
head
meta(charset='utf-8')
meta(http-equiv='x-ua-compatible', content='ie=edge')
title #{pkg.title} #{pkg.version} Demo
meta(name='description', content=`Demo for ${pkg.title} (${pkg.homepage}).`)
meta(name='viewport', content='width=device-width, initial-scale=1')
link(href='styles.css', rel='stylesheet')
link(href='//fonts.googleapis.com/css?family=Ubuntu:300,400,700', rel='stylesheet')
link(href='//fonts.googleapis.com/css2?family=Ubuntu+Mono:wght@400;700&display=swap' rel='stylesheet')
script(src='jquery.min.js')
script(src=`../jquery-qrcode-${pkg.version}.js`)
script(src='scripts.js')
@ -70,7 +69,7 @@ html(lang='en')
label(for='label') LABEL
input#label(type='text', value=pkg.title)
label(for='font') FONT NAME
input#font(type='text', value='Ubuntu')
input#font(type='text', value='Ubuntu Mono')
label(for='fontcolor') FONT COLOR
input#fontcolor(type='color', value='#ff9818')

@ -1,4 +1,4 @@
const WIN = window; // eslint-disable-line no-undef
const WIN = global.window;
const JQ = WIN.jQuery;
const GUI_VALUE_PAIRS = [
@ -71,12 +71,7 @@ const on_img_input = () => {
}
};
const download = () => {
JQ('#download').attr('href', JQ('#container canvas')[0].toDataURL('image/png'));
};
const init = () => {
JQ('#download').on('click', download);
JQ('#image').on('change', on_img_input);
JQ('input, textarea, select').on('input change', update);
JQ(WIN).on('load', update);

@ -1,7 +1,10 @@
body {
font-family: 'Ubuntu', 'sans';
* {
margin: 0;
padding: 0;
}
body {
font-family: 'Ubuntu Mono', 'monospace';
text-align: center;
background: repeat url('back.png');
}
@ -22,6 +25,7 @@ body {
display: inline-block;
margin: 20px auto;
box-shadow: 0 0 16px rgba(0,0,0,0.5);
-webkit-print-color-adjust: exact;
}
#container > * {
@ -55,26 +59,14 @@ hr {
}
label {
font-size: 10px;
color: #aaa;
padding: 12px 4px 0 4px;
}
#download {
text-align: center;
font-weight: bold;
text-decoration: none;
display: block;
font-size: 12px;
color: #555;
background-color: #ddd;
margin: 4px;
padding: 8px 0;
border: 1px solid #ddd;
cursor: pointer;
padding: 12px 4px 4px 4px;
}
input, textarea, select {
font-family: 'Ubuntu', 'sans';
font-family: 'Ubuntu Mono', 'monospace';
display: block;
background-color: #fff;
margin: 2px;
@ -104,3 +96,13 @@ input::-webkit-slider-thumb {
border-radius: 3px;
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #aaa), color-stop(1, #aaa));
}
@media print {
#container {
box-shadow: none;
}
.control {
display: none;
}
}

198
src/jquery-qrcode.js vendored

@ -1,21 +1,15 @@
const VQRCODE = require('./vqrcode');
const WIN = window; // eslint-disable-line no-undef
const WIN = window; // eslint-disable-line
const JQ = WIN.jQuery;
// Check if canvas is available in the browser (as Modernizr does)
const HAS_CANVAS = (() => {
const el = WIN.document.createElement('canvas');
return !!(el.getContext && el.getContext('2d'));
})();
const is_img_el = x => x && typeof x.tagName === 'string' && x.tagName.toUpperCase() === 'IMG';
// Wrapper for the original QR code generator.
const create_qrcode = (text, level, version, quiet) => {
const qr = {};
const vqr = VQRCODE(version, level);
const qr_gen = require('qrcode-generator');
qr_gen.stringToBytes = qr_gen.stringToBytesFuncs['UTF-8'];
const vqr = qr_gen(version, level);
vqr.addData(text);
vqr.make();
@ -66,14 +60,14 @@ const create_min_qrcode = (text, level, min_ver, max_ver, quiet) => {
return undefined;
};
const draw_background_label = (qr, context, settings) => {
const draw_background_label = (qr, ctx, settings) => {
const size = settings.size;
const font = 'bold ' + settings.mSize * size + 'px ' + settings.fontname;
const ctx = JQ('<canvas/>')[0].getContext('2d');
const tmp_ctx = JQ('<canvas/>')[0].getContext('2d');
ctx.font = font;
tmp_ctx.font = font;
const w = ctx.measureText(settings.label).width;
const w = tmp_ctx.measureText(settings.label).width;
const sh = settings.mSize;
const sw = w / size;
const sl = (1 - sw) * settings.mPosX;
@ -90,12 +84,12 @@ const draw_background_label = (qr, context, settings) => {
qr.add_blank(sl - pad, st - pad, sr + pad, sb + pad);
}
context.fillStyle = settings.fontcolor;
context.font = font;
context.fillText(settings.label, sl * size, st * size + 0.75 * settings.mSize * size);
ctx.fillStyle = settings.fontcolor;
ctx.font = font;
ctx.fillText(settings.label, sl * size, st * size + 0.75 * settings.mSize * size);
};
const draw_background_img = (qr, context, settings) => {
const draw_background_img = (qr, ctx, settings) => {
const size = settings.size;
const w = settings.image.naturalWidth || 1;
const h = settings.image.naturalHeight || 1;
@ -115,159 +109,150 @@ const draw_background_img = (qr, context, settings) => {
qr.add_blank(sl - pad, st - pad, sr + pad, sb + pad);
}
context.drawImage(settings.image, sl * size, st * size, sw * size, sh * size);
ctx.drawImage(settings.image, sl * size, st * size, sw * size, sh * size);
};
const draw_background = (qr, context, settings) => {
const draw_background = (qr, ctx, settings) => {
if (is_img_el(settings.background)) {
context.drawImage(settings.background, 0, 0, settings.size, settings.size);
ctx.drawImage(settings.background, 0, 0, settings.size, settings.size);
} else if (settings.background) {
context.fillStyle = settings.background;
context.fillRect(settings.left, settings.top, settings.size, settings.size);
ctx.fillStyle = settings.background;
ctx.fillRect(settings.left, settings.top, settings.size, settings.size);
}
const mode = settings.mode;
if (mode === 1 || mode === 2) {
draw_background_label(qr, context, settings);
draw_background_label(qr, ctx, settings);
} else if (is_img_el(settings.image) && (mode === 3 || mode === 4)) {
draw_background_img(qr, context, settings);
draw_background_img(qr, ctx, settings);
}
};
const draw_modules_default = (qr, context, settings, left, top, width, row, col) => {
const draw_modules_default = (qr, ctx, settings, left, top, width, row, col) => {
if (qr.is_dark(row, col)) {
context.rect(left, top, width, width);
ctx.r(left, top, width, width);
}
};
const draw_modules_rounded_dark = (ctx, l, t, r, b, rad, nw, ne, se, sw) => {
if (nw) {
ctx.moveTo(l + rad, t);
ctx.m(l + rad, t);
} else {
ctx.moveTo(l, t);
ctx.m(l, t);
}
if (ne) {
ctx.lineTo(r - rad, t);
ctx.arcTo(r, t, r, b, rad);
ctx.l(r - rad, t).a(r, t, r, b, rad);
} else {
ctx.lineTo(r, t);
ctx.l(r, t);
}
if (se) {
ctx.lineTo(r, b - rad);
ctx.arcTo(r, b, l, b, rad);
ctx.l(r, b - rad).a(r, b, l, b, rad);
} else {
ctx.lineTo(r, b);
ctx.l(r, b);
}
if (sw) {
ctx.lineTo(l + rad, b);
ctx.arcTo(l, b, l, t, rad);
ctx.l(l + rad, b).a(l, b, l, t, rad);
} else {
ctx.lineTo(l, b);
ctx.l(l, b);
}
if (nw) {
ctx.lineTo(l, t + rad);
ctx.arcTo(l, t, r, t, rad);
ctx.l(l, t + rad).a(l, t, r, t, rad);
} else {
ctx.lineTo(l, t);
ctx.l(l, t);
}
};
const draw_modules_rounded_light = (ctx, l, t, r, b, rad, nw, ne, se, sw) => {
if (nw) {
ctx.moveTo(l + rad, t);
ctx.lineTo(l, t);
ctx.lineTo(l, t + rad);
ctx.arcTo(l, t, l + rad, t, rad);
ctx.m(l + rad, t).l(l, t).l(l, t + rad).a(l, t, l + rad, t, rad);
}
if (ne) {
ctx.moveTo(r - rad, t);
ctx.lineTo(r, t);
ctx.lineTo(r, t + rad);
ctx.arcTo(r, t, r - rad, t, rad);
ctx.m(r - rad, t).l(r, t).l(r, t + rad).a(r, t, r - rad, t, rad);
}
if (se) {
ctx.moveTo(r - rad, b);
ctx.lineTo(r, b);
ctx.lineTo(r, b - rad);
ctx.arcTo(r, b, r - rad, b, rad);
ctx.m(r - rad, b).l(r, b).l(r, b - rad).a(r, b, r - rad, b, rad);
}
if (sw) {
ctx.moveTo(l + rad, b);
ctx.lineTo(l, b);
ctx.lineTo(l, b - rad);
ctx.arcTo(l, b, l + rad, b, rad);
ctx.m(l + rad, b).l(l, b).l(l, b - rad).a(l, b, l + rad, b, rad);
}
};
const draw_modules_rounded = (qr, context, settings, left, top, width, row, col) => {
const is_dark = qr.is_dark;
const draw_modules_rounded = (qr, ctx, settings, left, top, width, row, col) => {
const right = left + width;
const bottom = top + width;
const radius = settings.radius * width;
const rowT = row - 1;
const rowB = row + 1;
const colL = col - 1;
const colR = col + 1;
const center = is_dark(row, col);
const northwest = is_dark(rowT, colL);
const north = is_dark(rowT, col);
const northeast = is_dark(rowT, colR);
const east = is_dark(row, colR);
const southeast = is_dark(rowB, colR);
const south = is_dark(rowB, col);
const southwest = is_dark(rowB, colL);
const west = is_dark(row, colL);
if (center) {
draw_modules_rounded_dark(context, left, top, right, bottom, radius, !north && !west, !north && !east, !south && !east, !south && !west);
const rad = settings.radius * width;
const row_n = row - 1;
const row_s = row + 1;
const col_w = col - 1;
const col_e = col + 1;
const is_dark = qr.is_dark;
const d_center = is_dark(row, col);
const d_nw = is_dark(row_n, col_w);
const d_n = is_dark(row_n, col);
const d_ne = is_dark(row_n, col_e);
const d_e = is_dark(row, col_e);
const d_se = is_dark(row_s, col_e);
const d_s = is_dark(row_s, col);
const d_sw = is_dark(row_s, col_w);
const d_w = is_dark(row, col_w);
if (d_center) {
draw_modules_rounded_dark(ctx, left, top, right, bottom, rad, !d_n && !d_w, !d_n && !d_e, !d_s && !d_e, !d_s && !d_w);
} else {
draw_modules_rounded_light(context, left, top, right, bottom, radius, north && west && northwest, north && east && northeast, south && east && southeast, south && west && southwest);
draw_modules_rounded_light(ctx, left, top, right, bottom, rad, d_n && d_w && d_nw, d_n && d_e && d_ne, d_s && d_e && d_se, d_s && d_w && d_sw);
}
};
const draw_modules = (qr, context, settings) => {
const draw_modules = (qr, ctx, settings) => {
const module_count = qr.module_count;
const module_size = settings.size / module_count;
let fn = draw_modules_default;
let row;
let col;
let fn = draw_modules_default;
if (settings.radius > 0 && settings.radius <= 0.5) {
fn = draw_modules_rounded;
}
context.beginPath();
for (row = 0; row < module_count; row += 1) {
for (col = 0; col < module_count; col += 1) {
const draw_ctx = {
m(x, y) {ctx.moveTo(x, y); return draw_ctx;},
l(x, y) {ctx.lineTo(x, y); return draw_ctx;},
a(...args) {ctx.arcTo(...args); return draw_ctx;},
r(...args) {ctx.rect(...args); return draw_ctx;}
};
ctx.beginPath();
for (let row = 0; row < module_count; row += 1) {
for (let col = 0; col < module_count; col += 1) {
const l = settings.left + col * module_size;
const t = settings.top + row * module_size;
const w = module_size;
fn(qr, context, settings, l, t, w, row, col);
fn(qr, draw_ctx, settings, l, t, w, row, col);
}
}
if (is_img_el(settings.fill)) {
context.strokeStyle = 'rgba(0,0,0,0.5)';
context.lineWidth = 2;
context.stroke();
const prev = context.globalCompositeOperation;
context.globalCompositeOperation = 'destination-out';
context.fill();
context.globalCompositeOperation = prev;
context.clip();
context.drawImage(settings.fill, 0, 0, settings.size, settings.size);
context.restore();
ctx.strokeStyle = 'rgba(0,0,0,0.5)';
ctx.lineWidth = 2;
ctx.stroke();
const prev = ctx.globalCompositeOperation;
ctx.globalCompositeOperation = 'destination-out';
ctx.fill();
ctx.globalCompositeOperation = prev;
ctx.clip();
ctx.drawImage(settings.fill, 0, 0, settings.size, settings.size);
ctx.restore();
} else {
context.fillStyle = settings.fill;
context.fill();
ctx.fillStyle = settings.fill;
ctx.fill();
}
};
@ -279,10 +264,10 @@ const draw_on_canvas = (canvas, settings) => {
}
const $canvas = JQ(canvas).data('qrcode', qr);
const context = $canvas[0].getContext('2d');
const ctx = $canvas[0].getContext('2d');
draw_background(qr, context, settings);
draw_modules(qr, context, settings);
draw_background(qr, ctx, settings);
draw_modules(qr, ctx, settings);
return $canvas;
};
@ -314,9 +299,6 @@ const create_div = settings => {
const module_size = math_floor(settings_size / module_count);
const offset = math_floor(0.5 * (settings_size - module_size * module_count));
let row;
let col;
const container_css = {
position: 'relative',
left: 0,
@ -341,8 +323,8 @@ const create_div = settings => {
$div.css('background-color', settings_bgColor);
}
for (row = 0; row < module_count; row += 1) {
for (col = 0; col < module_count; col += 1) {
for (let row = 0; row < module_count; row += 1) {
for (let col = 0; col < module_count; col += 1) {
if (qr.is_dark(row, col)) {
JQ('<div/>')
.css(dark_css)
@ -359,9 +341,9 @@ const create_div = settings => {
};
const create_html = settings => {
if (HAS_CANVAS && settings.render === 'canvas') {
if (settings.render === 'canvas') {
return create_canvas(settings);
} else if (HAS_CANVAS && settings.render === 'image') {
} else if (settings.render === 'image') {
return create_img(settings);
}

@ -1,2 +0,0 @@
// @include "../vendor/qrcode.js"
// @include "../vendor/qrcode_UTF8.js"

1824
vendor/qrcode.js vendored

File diff suppressed because it is too large Load Diff

@ -1,59 +0,0 @@
//---------------------------------------------------------------------
//
// QR Code Generator for JavaScript UTF8 Support (optional)
//
// Copyright (c) 2011 Kazuhiko Arase
//
// URL: http://www.d-project.com/
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license.php
//
// The word 'QR Code' is registered trademark of
// DENSO WAVE INCORPORATED
// http://www.denso-wave.com/qrcode/faqpatent-e.html
//
//---------------------------------------------------------------------
!function(qrcode) {
//---------------------------------------------------------------------
// overwrite qrcode.stringToBytes
//---------------------------------------------------------------------
qrcode.stringToBytes = function(s) {
// http://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array
function toUTF8Array(str) {
var utf8 = [];
for (var i=0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) utf8.push(charcode);
else if (charcode < 0x800) {
utf8.push(0xc0 | (charcode >> 6),
0x80 | (charcode & 0x3f));
}
else if (charcode < 0xd800 || charcode >= 0xe000) {
utf8.push(0xe0 | (charcode >> 12),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f));
}
// surrogate pair
else {
i++;
// UTF-16 encodes 0x10000-0x10FFFF by
// subtracting 0x10000 and splitting the
// 20 bits of 0x0-0xFFFFF into two halves
charcode = 0x10000 + (((charcode & 0x3ff)<<10)
| (str.charCodeAt(i) & 0x3ff));
utf8.push(0xf0 | (charcode >>18),
0x80 | ((charcode>>12) & 0x3f),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f));
}
}
return utf8;
}
return toUTF8Array(s);
};
}(qrcode);
Loading…
Cancel
Save