qrcode.vue 3.7.0 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +140 -0
- package/dist/qrcode.vue.browser.js +95 -147
- package/dist/qrcode.vue.browser.min.js +2 -2
- package/dist/qrcode.vue.cjs.js +95 -147
- package/dist/qrcode.vue.esm.js +96 -148
- package/package.json +2 -1
package/dist/qrcode.vue.esm.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* qrcode.vue v3.
|
|
2
|
+
* qrcode.vue v3.8.0
|
|
3
3
|
* A Vue.js component to generate QRCode. Both support Vue 2 and Vue 3
|
|
4
4
|
* © 2017-PRESENT @scopewu(https://github.com/scopewu)
|
|
5
5
|
* MIT License.
|
|
6
6
|
*/
|
|
7
|
-
import { defineComponent,
|
|
7
|
+
import { defineComponent, h, ref, onMounted, watchEffect, Fragment, computed } from 'vue';
|
|
8
8
|
|
|
9
9
|
/******************************************************************************
|
|
10
10
|
Copyright (c) Microsoft Corporation.
|
|
@@ -909,6 +909,7 @@ var defaultErrorCorrectLevel = 'L';
|
|
|
909
909
|
var DEFAULT_QR_SIZE = 100;
|
|
910
910
|
var DEFAULT_MARGIN = 0;
|
|
911
911
|
var DEFAULT_IMAGE_SIZE_RATIO = 0.1;
|
|
912
|
+
var IMAGE_EXCAVATE_THICKNESS = 2;
|
|
912
913
|
var ErrorCorrectLevelMap = {
|
|
913
914
|
L: QR.QrCode.Ecc.LOW,
|
|
914
915
|
M: QR.QrCode.Ecc.MEDIUM,
|
|
@@ -928,42 +929,6 @@ var SUPPORTS_PATH2D = (function () {
|
|
|
928
929
|
function validErrorCorrectLevel(level) {
|
|
929
930
|
return level in ErrorCorrectLevelMap;
|
|
930
931
|
}
|
|
931
|
-
function isPointInRoundedRect(px, py, rx, ry, rw, rh, r) {
|
|
932
|
-
// Fast check: point outside the bounding box
|
|
933
|
-
if (px < rx || px > rx + rw || py < ry || py > ry + rh) {
|
|
934
|
-
return false;
|
|
935
|
-
}
|
|
936
|
-
// If no border radius or point is in the center rectangle
|
|
937
|
-
if (r <= 0 || (px > rx + r && px < rx + rw - r) || (py > ry + r && py < ry + rh - r)) {
|
|
938
|
-
return true;
|
|
939
|
-
}
|
|
940
|
-
// Check the four corners
|
|
941
|
-
// Top-left corner
|
|
942
|
-
if (px < rx + r && py < ry + r) {
|
|
943
|
-
var dx = px - (rx + r);
|
|
944
|
-
var dy = py - (ry + r);
|
|
945
|
-
return dx * dx + dy * dy <= r * r;
|
|
946
|
-
}
|
|
947
|
-
// Top-right corner
|
|
948
|
-
if (px > rx + rw - r && py < ry + r) {
|
|
949
|
-
var dx = px - (rx + rw - r);
|
|
950
|
-
var dy = py - (ry + r);
|
|
951
|
-
return dx * dx + dy * dy <= r * r;
|
|
952
|
-
}
|
|
953
|
-
// Bottom-left corner
|
|
954
|
-
if (px < rx + r && py > ry + rh - r) {
|
|
955
|
-
var dx = px - (rx + r);
|
|
956
|
-
var dy = py - (ry + rh - r);
|
|
957
|
-
return dx * dx + dy * dy <= r * r;
|
|
958
|
-
}
|
|
959
|
-
// Bottom-right corner
|
|
960
|
-
if (px > rx + rw - r && py > ry + rh - r) {
|
|
961
|
-
var dx = px - (rx + rw - r);
|
|
962
|
-
var dy = py - (ry + rh - r);
|
|
963
|
-
return dx * dx + dy * dy <= r * r;
|
|
964
|
-
}
|
|
965
|
-
return true;
|
|
966
|
-
}
|
|
967
932
|
function generatePath(modules, margin) {
|
|
968
933
|
if (margin === void 0) { margin = 0; }
|
|
969
934
|
var path = '';
|
|
@@ -1010,42 +975,51 @@ function getImageSettings(cells, size, margin, imageSettings) {
|
|
|
1010
975
|
var h = (height || defaultSize) * scale;
|
|
1011
976
|
var x = imageX == null ? cells.length / 2 - w / 2 : imageX * scale;
|
|
1012
977
|
var y = imageY == null ? cells.length / 2 - h / 2 : imageY * scale;
|
|
978
|
+
var borderRadius = (imageSettings.borderRadius || 0) * scale;
|
|
1013
979
|
var excavation = null;
|
|
1014
980
|
if (imageSettings.excavate) {
|
|
1015
981
|
var floorX = Math.floor(x);
|
|
1016
982
|
var floorY = Math.floor(y);
|
|
1017
983
|
var ceilW = Math.ceil(w + x - floorX);
|
|
1018
984
|
var ceilH = Math.ceil(h + y - floorY);
|
|
1019
|
-
|
|
1020
|
-
excavation = { x: floorX, y: floorY, w: ceilW, h: ceilH, borderRadius: borderRadius };
|
|
985
|
+
excavation = { x: floorX, y: floorY, w: ceilW, h: ceilH };
|
|
1021
986
|
}
|
|
1022
|
-
return { x: x, y: y, h: h, w: w, excavation: excavation };
|
|
987
|
+
return { x: x, y: y, h: h, w: w, borderRadius: borderRadius, excavation: excavation };
|
|
1023
988
|
}
|
|
1024
|
-
function
|
|
1025
|
-
var
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
return
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
return cell;
|
|
1045
|
-
var inExcavation = isPointInRoundedRect(x + 0.5, y + 0.5, excavation.x, excavation.y, excavation.w, excavation.h, borderRadius);
|
|
1046
|
-
return inExcavation ? false : cell;
|
|
1047
|
-
});
|
|
989
|
+
function useQRCode(props) {
|
|
990
|
+
var margin = computed(function () { var _a; return ((_a = props.margin) !== null && _a !== void 0 ? _a : DEFAULT_MARGIN) >>> 0; });
|
|
991
|
+
var cells = computed(function () {
|
|
992
|
+
var level = validErrorCorrectLevel(props.level) ? props.level : defaultErrorCorrectLevel;
|
|
993
|
+
return QR.QrCode.encodeText(props.value, ErrorCorrectLevelMap[level]).getModules();
|
|
994
|
+
});
|
|
995
|
+
var numCells = computed(function () { return cells.value.length + margin.value * 2; });
|
|
996
|
+
var fgPath = computed(function () { return generatePath(cells.value, margin.value); });
|
|
997
|
+
var imageProps = computed(function () {
|
|
998
|
+
if (!props.imageSettings.src) {
|
|
999
|
+
return { x: 0, y: 0, width: 0, height: 0, borderRadius: 0 };
|
|
1000
|
+
}
|
|
1001
|
+
var settings = getImageSettings(cells.value, props.size, margin.value, props.imageSettings);
|
|
1002
|
+
return {
|
|
1003
|
+
x: settings.x + margin.value,
|
|
1004
|
+
y: settings.y + margin.value,
|
|
1005
|
+
width: settings.w,
|
|
1006
|
+
height: settings.h,
|
|
1007
|
+
borderRadius: settings.borderRadius,
|
|
1008
|
+
};
|
|
1048
1009
|
});
|
|
1010
|
+
var imageBorderProps = computed(function () {
|
|
1011
|
+
if (!props.imageSettings.excavate || !props.imageSettings.src)
|
|
1012
|
+
return null;
|
|
1013
|
+
var borderThickness = IMAGE_EXCAVATE_THICKNESS / (props.size / numCells.value);
|
|
1014
|
+
return {
|
|
1015
|
+
x: imageProps.value.x - borderThickness,
|
|
1016
|
+
y: imageProps.value.y - borderThickness,
|
|
1017
|
+
width: imageProps.value.width + borderThickness * 2,
|
|
1018
|
+
height: imageProps.value.height + borderThickness * 2,
|
|
1019
|
+
borderRadius: imageProps.value.borderRadius,
|
|
1020
|
+
};
|
|
1021
|
+
});
|
|
1022
|
+
return { margin: margin, numCells: numCells, cells: cells, fgPath: fgPath, imageProps: imageProps, imageBorderProps: imageBorderProps };
|
|
1049
1023
|
}
|
|
1050
1024
|
var QRCodeProps = {
|
|
1051
1025
|
value: {
|
|
@@ -1112,35 +1086,8 @@ var QrcodeSvg = defineComponent({
|
|
|
1112
1086
|
name: 'QRCodeSvg',
|
|
1113
1087
|
props: QRCodeProps,
|
|
1114
1088
|
setup: function (props) {
|
|
1115
|
-
var
|
|
1116
|
-
var
|
|
1117
|
-
var imageProps;
|
|
1118
|
-
var generate = function () {
|
|
1119
|
-
var value = props.value, _level = props.level, _margin = props.margin;
|
|
1120
|
-
var margin = _margin >>> 0;
|
|
1121
|
-
var level = validErrorCorrectLevel(_level) ? _level : defaultErrorCorrectLevel;
|
|
1122
|
-
var cells = QR.QrCode.encodeText(value, ErrorCorrectLevelMap[level]).getModules();
|
|
1123
|
-
numCells.value = cells.length + margin * 2;
|
|
1124
|
-
if (props.imageSettings.src) {
|
|
1125
|
-
var imageSettings = getImageSettings(cells, props.size, margin, props.imageSettings);
|
|
1126
|
-
imageProps = {
|
|
1127
|
-
x: imageSettings.x + margin,
|
|
1128
|
-
y: imageSettings.y + margin,
|
|
1129
|
-
width: imageSettings.w,
|
|
1130
|
-
height: imageSettings.h,
|
|
1131
|
-
};
|
|
1132
|
-
if (imageSettings.excavation) {
|
|
1133
|
-
cells = excavateModules(cells, imageSettings.excavation);
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
// Drawing strategy: instead of a rect per module, we're going to create a
|
|
1137
|
-
// single path for the dark modules and layer that on top of a light rect,
|
|
1138
|
-
// for a total of 2 DOM nodes. We pay a bit more in string concat but that's
|
|
1139
|
-
// way faster than DOM ops.
|
|
1140
|
-
// For level 1, 441 nodes -> 2
|
|
1141
|
-
// For level 40, 31329 -> 2
|
|
1142
|
-
fgPath.value = generatePath(cells, margin);
|
|
1143
|
-
};
|
|
1089
|
+
var _a = useQRCode(props), numCells = _a.numCells, fgPath = _a.fgPath, imageProps = _a.imageProps, imageBorderProps = _a.imageBorderProps;
|
|
1090
|
+
var qrGradientId = 'qrcode.vue-gradient';
|
|
1144
1091
|
var renderGradient = function () {
|
|
1145
1092
|
if (!props.gradient)
|
|
1146
1093
|
return null;
|
|
@@ -1158,7 +1105,7 @@ var QrcodeSvg = defineComponent({
|
|
|
1158
1105
|
fx: '50%',
|
|
1159
1106
|
fy: '50%',
|
|
1160
1107
|
};
|
|
1161
|
-
return h(props.gradientType === 'linear' ? 'linearGradient' : 'radialGradient', __assign({ id:
|
|
1108
|
+
return h(props.gradientType === 'linear' ? 'linearGradient' : 'radialGradient', __assign({ id: qrGradientId }, gradientProps), [
|
|
1162
1109
|
h('stop', {
|
|
1163
1110
|
offset: '0%',
|
|
1164
1111
|
style: { stopColor: props.gradientStartColor },
|
|
@@ -1169,25 +1116,24 @@ var QrcodeSvg = defineComponent({
|
|
|
1169
1116
|
}),
|
|
1170
1117
|
]);
|
|
1171
1118
|
};
|
|
1119
|
+
var qrLogoClipPathId = 'qrcode.vue-logo-clip-path';
|
|
1172
1120
|
var renderClipPath = function () {
|
|
1173
|
-
var borderRadius =
|
|
1121
|
+
var borderRadius = imageProps.value.borderRadius;
|
|
1174
1122
|
if (!props.imageSettings.src)
|
|
1175
1123
|
return null;
|
|
1176
1124
|
if (borderRadius <= 0)
|
|
1177
1125
|
return null;
|
|
1178
|
-
return h('clipPath', { id:
|
|
1126
|
+
return h('clipPath', { id: qrLogoClipPathId }, [
|
|
1179
1127
|
h('rect', {
|
|
1180
|
-
x: imageProps.x,
|
|
1181
|
-
y: imageProps.y,
|
|
1182
|
-
width: imageProps.width,
|
|
1183
|
-
height: imageProps.height,
|
|
1128
|
+
x: imageProps.value.x,
|
|
1129
|
+
y: imageProps.value.y,
|
|
1130
|
+
width: imageProps.value.width,
|
|
1131
|
+
height: imageProps.value.height,
|
|
1184
1132
|
rx: borderRadius,
|
|
1185
1133
|
ry: borderRadius,
|
|
1186
1134
|
}),
|
|
1187
1135
|
]);
|
|
1188
1136
|
};
|
|
1189
|
-
generate();
|
|
1190
|
-
watch(props, generate, { deep: true });
|
|
1191
1137
|
return function () { return h('svg', {
|
|
1192
1138
|
width: props.size,
|
|
1193
1139
|
height: props.size,
|
|
@@ -1202,10 +1148,19 @@ var QrcodeSvg = defineComponent({
|
|
|
1202
1148
|
fill: props.background,
|
|
1203
1149
|
}),
|
|
1204
1150
|
h('path', {
|
|
1205
|
-
fill: props.gradient ?
|
|
1151
|
+
fill: props.gradient ? "url(#".concat(qrGradientId, ")") : props.foreground,
|
|
1206
1152
|
d: fgPath.value,
|
|
1207
1153
|
}),
|
|
1208
|
-
|
|
1154
|
+
imageBorderProps.value && h('rect', {
|
|
1155
|
+
x: imageBorderProps.value.x,
|
|
1156
|
+
y: imageBorderProps.value.y,
|
|
1157
|
+
width: imageBorderProps.value.width,
|
|
1158
|
+
height: imageBorderProps.value.height,
|
|
1159
|
+
fill: props.background,
|
|
1160
|
+
rx: imageBorderProps.value.borderRadius,
|
|
1161
|
+
ry: imageBorderProps.value.borderRadius,
|
|
1162
|
+
}),
|
|
1163
|
+
props.imageSettings.src && h('image', __assign(__assign({ href: props.imageSettings.src }, imageProps.value), (imageProps.value.borderRadius > 0 ? { 'clip-path': "url(#".concat(qrLogoClipPathId, ")") } : {}))),
|
|
1209
1164
|
]); };
|
|
1210
1165
|
},
|
|
1211
1166
|
});
|
|
@@ -1213,93 +1168,86 @@ var QrcodeCanvas = defineComponent({
|
|
|
1213
1168
|
name: 'QRCodeCanvas',
|
|
1214
1169
|
props: QRCodeProps,
|
|
1215
1170
|
setup: function (props, ctx) {
|
|
1171
|
+
var _a = useQRCode(props), margin = _a.margin, cells = _a.cells, numCells = _a.numCells, imageProps = _a.imageProps, imageBorderProps = _a.imageBorderProps;
|
|
1216
1172
|
var canvasEl = ref(null);
|
|
1217
1173
|
var imageRef = ref(null);
|
|
1218
1174
|
var generate = function () {
|
|
1219
|
-
var
|
|
1220
|
-
var margin = _margin >>> 0;
|
|
1221
|
-
var level = validErrorCorrectLevel(_level) ? _level : defaultErrorCorrectLevel;
|
|
1175
|
+
var size = props.size, background = props.background, foreground = props.foreground, gradient = props.gradient, gradientType = props.gradientType, gradientStartColor = props.gradientStartColor, gradientEndColor = props.gradientEndColor;
|
|
1222
1176
|
var canvas = canvasEl.value;
|
|
1223
1177
|
if (!canvas) {
|
|
1224
1178
|
return;
|
|
1225
1179
|
}
|
|
1226
|
-
var
|
|
1227
|
-
if (!
|
|
1180
|
+
var canvasCtx = canvas.getContext('2d');
|
|
1181
|
+
if (!canvasCtx) {
|
|
1228
1182
|
return;
|
|
1229
1183
|
}
|
|
1230
|
-
var
|
|
1231
|
-
var numCells = cells.length + margin * 2;
|
|
1184
|
+
var qrCells = cells.value;
|
|
1232
1185
|
var image = imageRef.value;
|
|
1233
|
-
var imageProps = { x: 0, y: 0, width: 0, height: 0 };
|
|
1234
|
-
var showImage = props.imageSettings.src && image != null && image.naturalWidth !== 0 && image.naturalHeight !== 0;
|
|
1235
|
-
if (showImage) {
|
|
1236
|
-
var imageSettings = getImageSettings(cells, props.size, margin, props.imageSettings);
|
|
1237
|
-
imageProps = {
|
|
1238
|
-
x: imageSettings.x + margin,
|
|
1239
|
-
y: imageSettings.y + margin,
|
|
1240
|
-
width: imageSettings.w,
|
|
1241
|
-
height: imageSettings.h,
|
|
1242
|
-
};
|
|
1243
|
-
if (imageSettings.excavation) {
|
|
1244
|
-
cells = excavateModules(cells, imageSettings.excavation);
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
1186
|
var devicePixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1;
|
|
1248
|
-
var scale = (size / numCells) * devicePixelRatio;
|
|
1187
|
+
var scale = (size / numCells.value) * devicePixelRatio;
|
|
1249
1188
|
canvas.height = canvas.width = size * devicePixelRatio;
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1189
|
+
canvasCtx.scale(scale, scale);
|
|
1190
|
+
canvasCtx.fillStyle = background;
|
|
1191
|
+
canvasCtx.fillRect(0, 0, numCells.value, numCells.value);
|
|
1253
1192
|
if (gradient) {
|
|
1254
1193
|
var grad = void 0;
|
|
1255
1194
|
if (gradientType === 'linear') {
|
|
1256
|
-
grad =
|
|
1195
|
+
grad = canvasCtx.createLinearGradient(0, 0, numCells.value, numCells.value);
|
|
1257
1196
|
}
|
|
1258
1197
|
else {
|
|
1259
|
-
grad =
|
|
1198
|
+
grad = canvasCtx.createRadialGradient(numCells.value / 2, numCells.value / 2, 0, numCells.value / 2, numCells.value / 2, numCells.value / 2);
|
|
1260
1199
|
}
|
|
1261
1200
|
grad.addColorStop(0, gradientStartColor);
|
|
1262
1201
|
grad.addColorStop(1, gradientEndColor);
|
|
1263
|
-
|
|
1202
|
+
canvasCtx.fillStyle = grad;
|
|
1264
1203
|
}
|
|
1265
1204
|
else {
|
|
1266
|
-
|
|
1205
|
+
canvasCtx.fillStyle = foreground;
|
|
1267
1206
|
}
|
|
1268
1207
|
if (SUPPORTS_PATH2D) {
|
|
1269
|
-
|
|
1208
|
+
canvasCtx.fill(new Path2D(generatePath(qrCells, margin.value)));
|
|
1270
1209
|
}
|
|
1271
1210
|
else {
|
|
1272
|
-
|
|
1211
|
+
qrCells.forEach(function (row, rdx) {
|
|
1273
1212
|
row.forEach(function (cell, cdx) {
|
|
1274
1213
|
if (cell) {
|
|
1275
|
-
|
|
1214
|
+
canvasCtx.fillRect(cdx + margin.value, rdx + margin.value, 1, 1);
|
|
1276
1215
|
}
|
|
1277
1216
|
});
|
|
1278
1217
|
});
|
|
1279
1218
|
}
|
|
1219
|
+
var showImage = props.imageSettings.src && image && image.naturalWidth !== 0 && image.naturalHeight !== 0;
|
|
1280
1220
|
if (showImage) {
|
|
1281
|
-
var
|
|
1282
|
-
if (borderRadius > 0) {
|
|
1283
|
-
ctx.save();
|
|
1221
|
+
var drawRoundedRect = function (ctx, x, y, width, height, radius) {
|
|
1284
1222
|
ctx.beginPath();
|
|
1285
1223
|
if (ctx.roundRect) {
|
|
1286
|
-
ctx.roundRect(
|
|
1224
|
+
ctx.roundRect(x, y, width, height, radius);
|
|
1287
1225
|
}
|
|
1288
1226
|
else {
|
|
1289
|
-
|
|
1290
|
-
ctx.rect(imageProps.x, imageProps.y, imageProps.width, imageProps.height);
|
|
1227
|
+
ctx.rect(x, y, width, height);
|
|
1291
1228
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1229
|
+
};
|
|
1230
|
+
if (imageBorderProps.value) {
|
|
1231
|
+
var imageBorder = imageBorderProps.value;
|
|
1232
|
+
canvasCtx.fillStyle = props.background;
|
|
1233
|
+
drawRoundedRect(canvasCtx, imageBorder.x, imageBorder.y, imageBorder.width, imageBorder.height, imageBorder.borderRadius);
|
|
1234
|
+
canvasCtx.fill();
|
|
1235
|
+
}
|
|
1236
|
+
var borderRadius = imageProps.value.borderRadius;
|
|
1237
|
+
if (borderRadius > 0) {
|
|
1238
|
+
canvasCtx.save();
|
|
1239
|
+
drawRoundedRect(canvasCtx, imageProps.value.x, imageProps.value.y, imageProps.value.width, imageProps.value.height, borderRadius);
|
|
1240
|
+
canvasCtx.clip();
|
|
1241
|
+
canvasCtx.drawImage(image, imageProps.value.x, imageProps.value.y, imageProps.value.width, imageProps.value.height);
|
|
1242
|
+
canvasCtx.restore();
|
|
1295
1243
|
}
|
|
1296
1244
|
else {
|
|
1297
|
-
|
|
1245
|
+
canvasCtx.drawImage(image, imageProps.value.x, imageProps.value.y, imageProps.value.width, imageProps.value.height);
|
|
1298
1246
|
}
|
|
1299
1247
|
}
|
|
1300
1248
|
};
|
|
1301
1249
|
onMounted(generate);
|
|
1302
|
-
|
|
1250
|
+
watchEffect(generate);
|
|
1303
1251
|
var style = ctx.attrs.style;
|
|
1304
1252
|
return function () { return h(Fragment, [
|
|
1305
1253
|
h('canvas', __assign(__assign({}, ctx.attrs), { ref: canvasEl, style: __assign(__assign({}, style), { width: "".concat(props.size, "px"), height: "".concat(props.size, "px") }) })),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qrcode.vue",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.8.0",
|
|
4
4
|
"description": "A Vue.js component to generate QRCode. Both support Vue 2 and Vue 3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/qrcode.vue.cjs.js",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
],
|
|
35
35
|
"files": [
|
|
36
36
|
"/dist",
|
|
37
|
+
"CHANGELOG.md",
|
|
37
38
|
"README-zh_cn.md",
|
|
38
39
|
"README.md"
|
|
39
40
|
],
|