qrcode.vue 3.6.0 → 3.7.1
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 +23 -0
- package/README-zh_cn.md +1 -0
- package/README.md +1 -0
- package/dist/qrcode.vue.browser.js +121 -31
- package/dist/qrcode.vue.browser.min.js +2 -2
- package/dist/qrcode.vue.cjs.js +121 -31
- package/dist/qrcode.vue.esm.js +122 -32
- package/dist/rstest.config.d.ts +2 -0
- package/dist/{index.d.ts → src/index.d.ts} +1 -0
- package/package.json +13 -10
- package/README-ja.md +0 -267
- /package/dist/{qrcodegen.d.ts → src/qrcodegen.d.ts} +0 -0
package/dist/qrcode.vue.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* qrcode.vue v3.
|
|
2
|
+
* qrcode.vue v3.7.1
|
|
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.
|
|
@@ -910,6 +910,9 @@ var qrcodegen;
|
|
|
910
910
|
var QR = qrcodegen;
|
|
911
911
|
|
|
912
912
|
var defaultErrorCorrectLevel = 'L';
|
|
913
|
+
var DEFAULT_QR_SIZE = 100;
|
|
914
|
+
var DEFAULT_MARGIN = 0;
|
|
915
|
+
var DEFAULT_IMAGE_SIZE_RATIO = 0.1;
|
|
913
916
|
var ErrorCorrectLevelMap = {
|
|
914
917
|
L: QR.QrCode.Ecc.LOW,
|
|
915
918
|
M: QR.QrCode.Ecc.MEDIUM,
|
|
@@ -929,16 +932,52 @@ var SUPPORTS_PATH2D = (function () {
|
|
|
929
932
|
function validErrorCorrectLevel(level) {
|
|
930
933
|
return level in ErrorCorrectLevelMap;
|
|
931
934
|
}
|
|
935
|
+
function isPointInRoundedRect(px, py, rx, ry, rw, rh, r) {
|
|
936
|
+
// Fast check: point outside the bounding box
|
|
937
|
+
if (px < rx || px > rx + rw || py < ry || py > ry + rh) {
|
|
938
|
+
return false;
|
|
939
|
+
}
|
|
940
|
+
// If no border radius or point is in the center rectangle
|
|
941
|
+
if (r <= 0 || (px > rx + r && px < rx + rw - r) || (py > ry + r && py < ry + rh - r)) {
|
|
942
|
+
return true;
|
|
943
|
+
}
|
|
944
|
+
// Check the four corners
|
|
945
|
+
// Top-left corner
|
|
946
|
+
if (px < rx + r && py < ry + r) {
|
|
947
|
+
var dx = px - (rx + r);
|
|
948
|
+
var dy = py - (ry + r);
|
|
949
|
+
return dx * dx + dy * dy <= r * r;
|
|
950
|
+
}
|
|
951
|
+
// Top-right corner
|
|
952
|
+
if (px > rx + rw - r && py < ry + r) {
|
|
953
|
+
var dx = px - (rx + rw - r);
|
|
954
|
+
var dy = py - (ry + r);
|
|
955
|
+
return dx * dx + dy * dy <= r * r;
|
|
956
|
+
}
|
|
957
|
+
// Bottom-left corner
|
|
958
|
+
if (px < rx + r && py > ry + rh - r) {
|
|
959
|
+
var dx = px - (rx + r);
|
|
960
|
+
var dy = py - (ry + rh - r);
|
|
961
|
+
return dx * dx + dy * dy <= r * r;
|
|
962
|
+
}
|
|
963
|
+
// Bottom-right corner
|
|
964
|
+
if (px > rx + rw - r && py > ry + rh - r) {
|
|
965
|
+
var dx = px - (rx + rw - r);
|
|
966
|
+
var dy = py - (ry + rh - r);
|
|
967
|
+
return dx * dx + dy * dy <= r * r;
|
|
968
|
+
}
|
|
969
|
+
return true;
|
|
970
|
+
}
|
|
932
971
|
function generatePath(modules, margin) {
|
|
933
972
|
if (margin === void 0) { margin = 0; }
|
|
934
|
-
var
|
|
973
|
+
var path = '';
|
|
935
974
|
modules.forEach(function (row, y) {
|
|
936
975
|
var start = null;
|
|
937
976
|
row.forEach(function (cell, x) {
|
|
938
977
|
if (!cell && start !== null) {
|
|
939
978
|
// M0 0h7v1H0z injects the space with the move and drops the comma,
|
|
940
979
|
// saving a char per operation
|
|
941
|
-
|
|
980
|
+
path += "M".concat(start + margin, " ").concat(y + margin, "h").concat(x - start, "v1H").concat(start + margin, "z");
|
|
942
981
|
start = null;
|
|
943
982
|
return;
|
|
944
983
|
}
|
|
@@ -951,11 +990,11 @@ function generatePath(modules, margin) {
|
|
|
951
990
|
}
|
|
952
991
|
if (start === null) {
|
|
953
992
|
// Just a single dark module.
|
|
954
|
-
|
|
993
|
+
path += "M".concat(x + margin, ",").concat(y + margin, " h1v1H").concat(x + margin, "z");
|
|
955
994
|
}
|
|
956
995
|
else {
|
|
957
996
|
// Otherwise finish the current line.
|
|
958
|
-
|
|
997
|
+
path += "M".concat(start + margin, ",").concat(y + margin, " h").concat(x + 1 - start, "v1H").concat(start + margin, "z");
|
|
959
998
|
}
|
|
960
999
|
return;
|
|
961
1000
|
}
|
|
@@ -964,17 +1003,18 @@ function generatePath(modules, margin) {
|
|
|
964
1003
|
}
|
|
965
1004
|
});
|
|
966
1005
|
});
|
|
967
|
-
return
|
|
1006
|
+
return path;
|
|
968
1007
|
}
|
|
969
1008
|
function getImageSettings(cells, size, margin, imageSettings) {
|
|
970
1009
|
var width = imageSettings.width, height = imageSettings.height, imageX = imageSettings.x, imageY = imageSettings.y;
|
|
971
1010
|
var numCells = cells.length + margin * 2;
|
|
972
|
-
var defaultSize = Math.floor(size *
|
|
1011
|
+
var defaultSize = Math.floor(size * DEFAULT_IMAGE_SIZE_RATIO);
|
|
973
1012
|
var scale = numCells / size;
|
|
974
1013
|
var w = (width || defaultSize) * scale;
|
|
975
1014
|
var h = (height || defaultSize) * scale;
|
|
976
1015
|
var x = imageX == null ? cells.length / 2 - w / 2 : imageX * scale;
|
|
977
1016
|
var y = imageY == null ? cells.length / 2 - h / 2 : imageY * scale;
|
|
1017
|
+
var borderRadius = (imageSettings.borderRadius || 0) * scale;
|
|
978
1018
|
var excavation = null;
|
|
979
1019
|
if (imageSettings.excavate) {
|
|
980
1020
|
var floorX = Math.floor(x);
|
|
@@ -983,18 +1023,30 @@ function getImageSettings(cells, size, margin, imageSettings) {
|
|
|
983
1023
|
var ceilH = Math.ceil(h + y - floorY);
|
|
984
1024
|
excavation = { x: floorX, y: floorY, w: ceilW, h: ceilH };
|
|
985
1025
|
}
|
|
986
|
-
return { x: x, y: y, h: h, w: w, excavation: excavation };
|
|
1026
|
+
return { x: x, y: y, h: h, w: w, borderRadius: borderRadius, excavation: excavation };
|
|
987
1027
|
}
|
|
988
|
-
function excavateModules(modules, excavation) {
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1028
|
+
function excavateModules(modules, excavation, borderRadius) {
|
|
1029
|
+
// If no border radius, use simple rectangular excavation
|
|
1030
|
+
if (!borderRadius || borderRadius <= 0) {
|
|
1031
|
+
return modules.map(function (row, y) {
|
|
1032
|
+
if (y < excavation.y || y >= excavation.y + excavation.h) {
|
|
1033
|
+
return row;
|
|
1034
|
+
}
|
|
1035
|
+
return row.map(function (cell, x) {
|
|
1036
|
+
if (x < excavation.x || x >= excavation.x + excavation.w) {
|
|
1037
|
+
return cell;
|
|
1038
|
+
}
|
|
1039
|
+
return false;
|
|
1040
|
+
});
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
// For rounded corners, check each module against the rounded rectangle shape
|
|
1044
|
+
return modules.map(function (row, y) {
|
|
993
1045
|
return row.map(function (cell, x) {
|
|
994
|
-
if (
|
|
1046
|
+
if (!cell)
|
|
995
1047
|
return cell;
|
|
996
|
-
|
|
997
|
-
return false;
|
|
1048
|
+
var inExcavation = isPointInRoundedRect(x + 0.5, y + 0.5, excavation.x, excavation.y, excavation.w, excavation.h, borderRadius);
|
|
1049
|
+
return inExcavation ? false : cell;
|
|
998
1050
|
});
|
|
999
1051
|
});
|
|
1000
1052
|
}
|
|
@@ -1006,7 +1058,7 @@ var QRCodeProps = {
|
|
|
1006
1058
|
},
|
|
1007
1059
|
size: {
|
|
1008
1060
|
type: Number,
|
|
1009
|
-
default:
|
|
1061
|
+
default: DEFAULT_QR_SIZE,
|
|
1010
1062
|
},
|
|
1011
1063
|
level: {
|
|
1012
1064
|
type: String,
|
|
@@ -1024,7 +1076,7 @@ var QRCodeProps = {
|
|
|
1024
1076
|
margin: {
|
|
1025
1077
|
type: Number,
|
|
1026
1078
|
required: false,
|
|
1027
|
-
default:
|
|
1079
|
+
default: DEFAULT_MARGIN,
|
|
1028
1080
|
},
|
|
1029
1081
|
imageSettings: {
|
|
1030
1082
|
type: Object,
|
|
@@ -1065,7 +1117,7 @@ var QrcodeSvg = vue.defineComponent({
|
|
|
1065
1117
|
setup: function (props) {
|
|
1066
1118
|
var numCells = vue.ref(0);
|
|
1067
1119
|
var fgPath = vue.ref('');
|
|
1068
|
-
var imageProps;
|
|
1120
|
+
var imageProps = vue.ref({ x: 0, y: 0, width: 0, height: 0, borderRadius: 0 });
|
|
1069
1121
|
var generate = function () {
|
|
1070
1122
|
var value = props.value, _level = props.level, _margin = props.margin;
|
|
1071
1123
|
var margin = _margin >>> 0;
|
|
@@ -1074,14 +1126,15 @@ var QrcodeSvg = vue.defineComponent({
|
|
|
1074
1126
|
numCells.value = cells.length + margin * 2;
|
|
1075
1127
|
if (props.imageSettings.src) {
|
|
1076
1128
|
var imageSettings = getImageSettings(cells, props.size, margin, props.imageSettings);
|
|
1077
|
-
imageProps = {
|
|
1129
|
+
imageProps.value = {
|
|
1078
1130
|
x: imageSettings.x + margin,
|
|
1079
1131
|
y: imageSettings.y + margin,
|
|
1080
1132
|
width: imageSettings.w,
|
|
1081
1133
|
height: imageSettings.h,
|
|
1134
|
+
borderRadius: imageSettings.borderRadius,
|
|
1082
1135
|
};
|
|
1083
1136
|
if (imageSettings.excavation) {
|
|
1084
|
-
cells = excavateModules(cells, imageSettings.excavation);
|
|
1137
|
+
cells = excavateModules(cells, imageSettings.excavation, imageSettings.borderRadius);
|
|
1085
1138
|
}
|
|
1086
1139
|
}
|
|
1087
1140
|
// Drawing strategy: instead of a rect per module, we're going to create a
|
|
@@ -1092,6 +1145,7 @@ var QrcodeSvg = vue.defineComponent({
|
|
|
1092
1145
|
// For level 40, 31329 -> 2
|
|
1093
1146
|
fgPath.value = generatePath(cells, margin);
|
|
1094
1147
|
};
|
|
1148
|
+
var qrGradientId = 'qrcode.vue-gradient';
|
|
1095
1149
|
var renderGradient = function () {
|
|
1096
1150
|
if (!props.gradient)
|
|
1097
1151
|
return null;
|
|
@@ -1109,7 +1163,7 @@ var QrcodeSvg = vue.defineComponent({
|
|
|
1109
1163
|
fx: '50%',
|
|
1110
1164
|
fy: '50%',
|
|
1111
1165
|
};
|
|
1112
|
-
return vue.h(props.gradientType === 'linear' ? 'linearGradient' : 'radialGradient', __assign({ id:
|
|
1166
|
+
return vue.h(props.gradientType === 'linear' ? 'linearGradient' : 'radialGradient', __assign({ id: qrGradientId }, gradientProps), [
|
|
1113
1167
|
vue.h('stop', {
|
|
1114
1168
|
offset: '0%',
|
|
1115
1169
|
style: { stopColor: props.gradientStartColor },
|
|
@@ -1120,8 +1174,26 @@ var QrcodeSvg = vue.defineComponent({
|
|
|
1120
1174
|
}),
|
|
1121
1175
|
]);
|
|
1122
1176
|
};
|
|
1177
|
+
var qrLogoClipPathId = 'qrcode.vue-logo-clip-path';
|
|
1178
|
+
var renderClipPath = function () {
|
|
1179
|
+
var borderRadius = imageProps.value.borderRadius;
|
|
1180
|
+
if (!props.imageSettings.src)
|
|
1181
|
+
return null;
|
|
1182
|
+
if (borderRadius <= 0)
|
|
1183
|
+
return null;
|
|
1184
|
+
return vue.h('clipPath', { id: qrLogoClipPathId }, [
|
|
1185
|
+
vue.h('rect', {
|
|
1186
|
+
x: imageProps.value.x,
|
|
1187
|
+
y: imageProps.value.y,
|
|
1188
|
+
width: imageProps.value.width,
|
|
1189
|
+
height: imageProps.value.height,
|
|
1190
|
+
rx: borderRadius,
|
|
1191
|
+
ry: borderRadius,
|
|
1192
|
+
}),
|
|
1193
|
+
]);
|
|
1194
|
+
};
|
|
1123
1195
|
generate();
|
|
1124
|
-
vue.
|
|
1196
|
+
vue.watch(props, generate, { deep: true });
|
|
1125
1197
|
return function () { return vue.h('svg', {
|
|
1126
1198
|
width: props.size,
|
|
1127
1199
|
height: props.size,
|
|
@@ -1129,17 +1201,17 @@ var QrcodeSvg = vue.defineComponent({
|
|
|
1129
1201
|
xmlns: 'http://www.w3.org/2000/svg',
|
|
1130
1202
|
viewBox: "0 0 ".concat(numCells.value, " ").concat(numCells.value),
|
|
1131
1203
|
}, [
|
|
1132
|
-
vue.h('defs', {}, [renderGradient()]),
|
|
1204
|
+
vue.h('defs', {}, [renderGradient(), renderClipPath()]),
|
|
1133
1205
|
vue.h('rect', {
|
|
1134
1206
|
width: '100%',
|
|
1135
1207
|
height: '100%',
|
|
1136
1208
|
fill: props.background,
|
|
1137
1209
|
}),
|
|
1138
1210
|
vue.h('path', {
|
|
1139
|
-
fill: props.gradient ?
|
|
1211
|
+
fill: props.gradient ? "url(#".concat(qrGradientId, ")") : props.foreground,
|
|
1140
1212
|
d: fgPath.value,
|
|
1141
1213
|
}),
|
|
1142
|
-
props.imageSettings.src && vue.h('image', __assign({ href: props.imageSettings.src }, imageProps)),
|
|
1214
|
+
props.imageSettings.src && vue.h('image', __assign(__assign({ href: props.imageSettings.src }, imageProps.value), (imageProps.value.borderRadius > 0 ? { 'clip-path': "url(#".concat(qrLogoClipPathId, ")") } : {}))),
|
|
1143
1215
|
]); };
|
|
1144
1216
|
},
|
|
1145
1217
|
});
|
|
@@ -1164,7 +1236,7 @@ var QrcodeCanvas = vue.defineComponent({
|
|
|
1164
1236
|
var cells = QR.QrCode.encodeText(value, ErrorCorrectLevelMap[level]).getModules();
|
|
1165
1237
|
var numCells = cells.length + margin * 2;
|
|
1166
1238
|
var image = imageRef.value;
|
|
1167
|
-
var imageProps = { x: 0, y: 0, width: 0, height: 0 };
|
|
1239
|
+
var imageProps = { x: 0, y: 0, width: 0, height: 0, borderRadius: 0 };
|
|
1168
1240
|
var showImage = props.imageSettings.src && image != null && image.naturalWidth !== 0 && image.naturalHeight !== 0;
|
|
1169
1241
|
if (showImage) {
|
|
1170
1242
|
var imageSettings = getImageSettings(cells, props.size, margin, props.imageSettings);
|
|
@@ -1173,12 +1245,13 @@ var QrcodeCanvas = vue.defineComponent({
|
|
|
1173
1245
|
y: imageSettings.y + margin,
|
|
1174
1246
|
width: imageSettings.w,
|
|
1175
1247
|
height: imageSettings.h,
|
|
1248
|
+
borderRadius: imageSettings.borderRadius,
|
|
1176
1249
|
};
|
|
1177
1250
|
if (imageSettings.excavation) {
|
|
1178
|
-
cells = excavateModules(cells, imageSettings.excavation);
|
|
1251
|
+
cells = excavateModules(cells, imageSettings.excavation, imageSettings.borderRadius);
|
|
1179
1252
|
}
|
|
1180
1253
|
}
|
|
1181
|
-
var devicePixelRatio = window.devicePixelRatio || 1;
|
|
1254
|
+
var devicePixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1;
|
|
1182
1255
|
var scale = (size / numCells) * devicePixelRatio;
|
|
1183
1256
|
canvas.height = canvas.width = size * devicePixelRatio;
|
|
1184
1257
|
ctx.scale(scale, scale);
|
|
@@ -1212,11 +1285,28 @@ var QrcodeCanvas = vue.defineComponent({
|
|
|
1212
1285
|
});
|
|
1213
1286
|
}
|
|
1214
1287
|
if (showImage) {
|
|
1215
|
-
|
|
1288
|
+
var borderRadius = imageProps.borderRadius;
|
|
1289
|
+
if (borderRadius > 0) {
|
|
1290
|
+
ctx.save();
|
|
1291
|
+
ctx.beginPath();
|
|
1292
|
+
if (ctx.roundRect) {
|
|
1293
|
+
ctx.roundRect(imageProps.x, imageProps.y, imageProps.width, imageProps.height, borderRadius);
|
|
1294
|
+
}
|
|
1295
|
+
else {
|
|
1296
|
+
// Fallback for browsers without roundRect support
|
|
1297
|
+
ctx.rect(imageProps.x, imageProps.y, imageProps.width, imageProps.height);
|
|
1298
|
+
}
|
|
1299
|
+
ctx.clip();
|
|
1300
|
+
ctx.drawImage(image, imageProps.x, imageProps.y, imageProps.width, imageProps.height);
|
|
1301
|
+
ctx.restore();
|
|
1302
|
+
}
|
|
1303
|
+
else {
|
|
1304
|
+
ctx.drawImage(image, imageProps.x, imageProps.y, imageProps.width, imageProps.height);
|
|
1305
|
+
}
|
|
1216
1306
|
}
|
|
1217
1307
|
};
|
|
1218
1308
|
vue.onMounted(generate);
|
|
1219
|
-
vue.
|
|
1309
|
+
vue.watch(props, generate, { deep: true });
|
|
1220
1310
|
var style = ctx.attrs.style;
|
|
1221
1311
|
return function () { return vue.h(vue.Fragment, [
|
|
1222
1312
|
vue.h('canvas', __assign(__assign({}, ctx.attrs), { ref: canvasEl, style: __assign(__assign({}, style), { width: "".concat(props.size, "px"), height: "".concat(props.size, "px") }) })),
|
package/dist/qrcode.vue.esm.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* qrcode.vue v3.
|
|
2
|
+
* qrcode.vue v3.7.1
|
|
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, ref,
|
|
7
|
+
import { defineComponent, ref, watch, h, onMounted, Fragment } from 'vue';
|
|
8
8
|
|
|
9
9
|
/******************************************************************************
|
|
10
10
|
Copyright (c) Microsoft Corporation.
|
|
@@ -906,6 +906,9 @@ var qrcodegen;
|
|
|
906
906
|
var QR = qrcodegen;
|
|
907
907
|
|
|
908
908
|
var defaultErrorCorrectLevel = 'L';
|
|
909
|
+
var DEFAULT_QR_SIZE = 100;
|
|
910
|
+
var DEFAULT_MARGIN = 0;
|
|
911
|
+
var DEFAULT_IMAGE_SIZE_RATIO = 0.1;
|
|
909
912
|
var ErrorCorrectLevelMap = {
|
|
910
913
|
L: QR.QrCode.Ecc.LOW,
|
|
911
914
|
M: QR.QrCode.Ecc.MEDIUM,
|
|
@@ -925,16 +928,52 @@ var SUPPORTS_PATH2D = (function () {
|
|
|
925
928
|
function validErrorCorrectLevel(level) {
|
|
926
929
|
return level in ErrorCorrectLevelMap;
|
|
927
930
|
}
|
|
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
|
+
}
|
|
928
967
|
function generatePath(modules, margin) {
|
|
929
968
|
if (margin === void 0) { margin = 0; }
|
|
930
|
-
var
|
|
969
|
+
var path = '';
|
|
931
970
|
modules.forEach(function (row, y) {
|
|
932
971
|
var start = null;
|
|
933
972
|
row.forEach(function (cell, x) {
|
|
934
973
|
if (!cell && start !== null) {
|
|
935
974
|
// M0 0h7v1H0z injects the space with the move and drops the comma,
|
|
936
975
|
// saving a char per operation
|
|
937
|
-
|
|
976
|
+
path += "M".concat(start + margin, " ").concat(y + margin, "h").concat(x - start, "v1H").concat(start + margin, "z");
|
|
938
977
|
start = null;
|
|
939
978
|
return;
|
|
940
979
|
}
|
|
@@ -947,11 +986,11 @@ function generatePath(modules, margin) {
|
|
|
947
986
|
}
|
|
948
987
|
if (start === null) {
|
|
949
988
|
// Just a single dark module.
|
|
950
|
-
|
|
989
|
+
path += "M".concat(x + margin, ",").concat(y + margin, " h1v1H").concat(x + margin, "z");
|
|
951
990
|
}
|
|
952
991
|
else {
|
|
953
992
|
// Otherwise finish the current line.
|
|
954
|
-
|
|
993
|
+
path += "M".concat(start + margin, ",").concat(y + margin, " h").concat(x + 1 - start, "v1H").concat(start + margin, "z");
|
|
955
994
|
}
|
|
956
995
|
return;
|
|
957
996
|
}
|
|
@@ -960,17 +999,18 @@ function generatePath(modules, margin) {
|
|
|
960
999
|
}
|
|
961
1000
|
});
|
|
962
1001
|
});
|
|
963
|
-
return
|
|
1002
|
+
return path;
|
|
964
1003
|
}
|
|
965
1004
|
function getImageSettings(cells, size, margin, imageSettings) {
|
|
966
1005
|
var width = imageSettings.width, height = imageSettings.height, imageX = imageSettings.x, imageY = imageSettings.y;
|
|
967
1006
|
var numCells = cells.length + margin * 2;
|
|
968
|
-
var defaultSize = Math.floor(size *
|
|
1007
|
+
var defaultSize = Math.floor(size * DEFAULT_IMAGE_SIZE_RATIO);
|
|
969
1008
|
var scale = numCells / size;
|
|
970
1009
|
var w = (width || defaultSize) * scale;
|
|
971
1010
|
var h = (height || defaultSize) * scale;
|
|
972
1011
|
var x = imageX == null ? cells.length / 2 - w / 2 : imageX * scale;
|
|
973
1012
|
var y = imageY == null ? cells.length / 2 - h / 2 : imageY * scale;
|
|
1013
|
+
var borderRadius = (imageSettings.borderRadius || 0) * scale;
|
|
974
1014
|
var excavation = null;
|
|
975
1015
|
if (imageSettings.excavate) {
|
|
976
1016
|
var floorX = Math.floor(x);
|
|
@@ -979,18 +1019,30 @@ function getImageSettings(cells, size, margin, imageSettings) {
|
|
|
979
1019
|
var ceilH = Math.ceil(h + y - floorY);
|
|
980
1020
|
excavation = { x: floorX, y: floorY, w: ceilW, h: ceilH };
|
|
981
1021
|
}
|
|
982
|
-
return { x: x, y: y, h: h, w: w, excavation: excavation };
|
|
1022
|
+
return { x: x, y: y, h: h, w: w, borderRadius: borderRadius, excavation: excavation };
|
|
983
1023
|
}
|
|
984
|
-
function excavateModules(modules, excavation) {
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1024
|
+
function excavateModules(modules, excavation, borderRadius) {
|
|
1025
|
+
// If no border radius, use simple rectangular excavation
|
|
1026
|
+
if (!borderRadius || borderRadius <= 0) {
|
|
1027
|
+
return modules.map(function (row, y) {
|
|
1028
|
+
if (y < excavation.y || y >= excavation.y + excavation.h) {
|
|
1029
|
+
return row;
|
|
1030
|
+
}
|
|
1031
|
+
return row.map(function (cell, x) {
|
|
1032
|
+
if (x < excavation.x || x >= excavation.x + excavation.w) {
|
|
1033
|
+
return cell;
|
|
1034
|
+
}
|
|
1035
|
+
return false;
|
|
1036
|
+
});
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
// For rounded corners, check each module against the rounded rectangle shape
|
|
1040
|
+
return modules.map(function (row, y) {
|
|
989
1041
|
return row.map(function (cell, x) {
|
|
990
|
-
if (
|
|
1042
|
+
if (!cell)
|
|
991
1043
|
return cell;
|
|
992
|
-
|
|
993
|
-
return false;
|
|
1044
|
+
var inExcavation = isPointInRoundedRect(x + 0.5, y + 0.5, excavation.x, excavation.y, excavation.w, excavation.h, borderRadius);
|
|
1045
|
+
return inExcavation ? false : cell;
|
|
994
1046
|
});
|
|
995
1047
|
});
|
|
996
1048
|
}
|
|
@@ -1002,7 +1054,7 @@ var QRCodeProps = {
|
|
|
1002
1054
|
},
|
|
1003
1055
|
size: {
|
|
1004
1056
|
type: Number,
|
|
1005
|
-
default:
|
|
1057
|
+
default: DEFAULT_QR_SIZE,
|
|
1006
1058
|
},
|
|
1007
1059
|
level: {
|
|
1008
1060
|
type: String,
|
|
@@ -1020,7 +1072,7 @@ var QRCodeProps = {
|
|
|
1020
1072
|
margin: {
|
|
1021
1073
|
type: Number,
|
|
1022
1074
|
required: false,
|
|
1023
|
-
default:
|
|
1075
|
+
default: DEFAULT_MARGIN,
|
|
1024
1076
|
},
|
|
1025
1077
|
imageSettings: {
|
|
1026
1078
|
type: Object,
|
|
@@ -1061,7 +1113,7 @@ var QrcodeSvg = defineComponent({
|
|
|
1061
1113
|
setup: function (props) {
|
|
1062
1114
|
var numCells = ref(0);
|
|
1063
1115
|
var fgPath = ref('');
|
|
1064
|
-
var imageProps;
|
|
1116
|
+
var imageProps = ref({ x: 0, y: 0, width: 0, height: 0, borderRadius: 0 });
|
|
1065
1117
|
var generate = function () {
|
|
1066
1118
|
var value = props.value, _level = props.level, _margin = props.margin;
|
|
1067
1119
|
var margin = _margin >>> 0;
|
|
@@ -1070,14 +1122,15 @@ var QrcodeSvg = defineComponent({
|
|
|
1070
1122
|
numCells.value = cells.length + margin * 2;
|
|
1071
1123
|
if (props.imageSettings.src) {
|
|
1072
1124
|
var imageSettings = getImageSettings(cells, props.size, margin, props.imageSettings);
|
|
1073
|
-
imageProps = {
|
|
1125
|
+
imageProps.value = {
|
|
1074
1126
|
x: imageSettings.x + margin,
|
|
1075
1127
|
y: imageSettings.y + margin,
|
|
1076
1128
|
width: imageSettings.w,
|
|
1077
1129
|
height: imageSettings.h,
|
|
1130
|
+
borderRadius: imageSettings.borderRadius,
|
|
1078
1131
|
};
|
|
1079
1132
|
if (imageSettings.excavation) {
|
|
1080
|
-
cells = excavateModules(cells, imageSettings.excavation);
|
|
1133
|
+
cells = excavateModules(cells, imageSettings.excavation, imageSettings.borderRadius);
|
|
1081
1134
|
}
|
|
1082
1135
|
}
|
|
1083
1136
|
// Drawing strategy: instead of a rect per module, we're going to create a
|
|
@@ -1088,6 +1141,7 @@ var QrcodeSvg = defineComponent({
|
|
|
1088
1141
|
// For level 40, 31329 -> 2
|
|
1089
1142
|
fgPath.value = generatePath(cells, margin);
|
|
1090
1143
|
};
|
|
1144
|
+
var qrGradientId = 'qrcode.vue-gradient';
|
|
1091
1145
|
var renderGradient = function () {
|
|
1092
1146
|
if (!props.gradient)
|
|
1093
1147
|
return null;
|
|
@@ -1105,7 +1159,7 @@ var QrcodeSvg = defineComponent({
|
|
|
1105
1159
|
fx: '50%',
|
|
1106
1160
|
fy: '50%',
|
|
1107
1161
|
};
|
|
1108
|
-
return h(props.gradientType === 'linear' ? 'linearGradient' : 'radialGradient', __assign({ id:
|
|
1162
|
+
return h(props.gradientType === 'linear' ? 'linearGradient' : 'radialGradient', __assign({ id: qrGradientId }, gradientProps), [
|
|
1109
1163
|
h('stop', {
|
|
1110
1164
|
offset: '0%',
|
|
1111
1165
|
style: { stopColor: props.gradientStartColor },
|
|
@@ -1116,8 +1170,26 @@ var QrcodeSvg = defineComponent({
|
|
|
1116
1170
|
}),
|
|
1117
1171
|
]);
|
|
1118
1172
|
};
|
|
1173
|
+
var qrLogoClipPathId = 'qrcode.vue-logo-clip-path';
|
|
1174
|
+
var renderClipPath = function () {
|
|
1175
|
+
var borderRadius = imageProps.value.borderRadius;
|
|
1176
|
+
if (!props.imageSettings.src)
|
|
1177
|
+
return null;
|
|
1178
|
+
if (borderRadius <= 0)
|
|
1179
|
+
return null;
|
|
1180
|
+
return h('clipPath', { id: qrLogoClipPathId }, [
|
|
1181
|
+
h('rect', {
|
|
1182
|
+
x: imageProps.value.x,
|
|
1183
|
+
y: imageProps.value.y,
|
|
1184
|
+
width: imageProps.value.width,
|
|
1185
|
+
height: imageProps.value.height,
|
|
1186
|
+
rx: borderRadius,
|
|
1187
|
+
ry: borderRadius,
|
|
1188
|
+
}),
|
|
1189
|
+
]);
|
|
1190
|
+
};
|
|
1119
1191
|
generate();
|
|
1120
|
-
|
|
1192
|
+
watch(props, generate, { deep: true });
|
|
1121
1193
|
return function () { return h('svg', {
|
|
1122
1194
|
width: props.size,
|
|
1123
1195
|
height: props.size,
|
|
@@ -1125,17 +1197,17 @@ var QrcodeSvg = defineComponent({
|
|
|
1125
1197
|
xmlns: 'http://www.w3.org/2000/svg',
|
|
1126
1198
|
viewBox: "0 0 ".concat(numCells.value, " ").concat(numCells.value),
|
|
1127
1199
|
}, [
|
|
1128
|
-
h('defs', {}, [renderGradient()]),
|
|
1200
|
+
h('defs', {}, [renderGradient(), renderClipPath()]),
|
|
1129
1201
|
h('rect', {
|
|
1130
1202
|
width: '100%',
|
|
1131
1203
|
height: '100%',
|
|
1132
1204
|
fill: props.background,
|
|
1133
1205
|
}),
|
|
1134
1206
|
h('path', {
|
|
1135
|
-
fill: props.gradient ?
|
|
1207
|
+
fill: props.gradient ? "url(#".concat(qrGradientId, ")") : props.foreground,
|
|
1136
1208
|
d: fgPath.value,
|
|
1137
1209
|
}),
|
|
1138
|
-
props.imageSettings.src && h('image', __assign({ href: props.imageSettings.src }, imageProps)),
|
|
1210
|
+
props.imageSettings.src && h('image', __assign(__assign({ href: props.imageSettings.src }, imageProps.value), (imageProps.value.borderRadius > 0 ? { 'clip-path': "url(#".concat(qrLogoClipPathId, ")") } : {}))),
|
|
1139
1211
|
]); };
|
|
1140
1212
|
},
|
|
1141
1213
|
});
|
|
@@ -1160,7 +1232,7 @@ var QrcodeCanvas = defineComponent({
|
|
|
1160
1232
|
var cells = QR.QrCode.encodeText(value, ErrorCorrectLevelMap[level]).getModules();
|
|
1161
1233
|
var numCells = cells.length + margin * 2;
|
|
1162
1234
|
var image = imageRef.value;
|
|
1163
|
-
var imageProps = { x: 0, y: 0, width: 0, height: 0 };
|
|
1235
|
+
var imageProps = { x: 0, y: 0, width: 0, height: 0, borderRadius: 0 };
|
|
1164
1236
|
var showImage = props.imageSettings.src && image != null && image.naturalWidth !== 0 && image.naturalHeight !== 0;
|
|
1165
1237
|
if (showImage) {
|
|
1166
1238
|
var imageSettings = getImageSettings(cells, props.size, margin, props.imageSettings);
|
|
@@ -1169,12 +1241,13 @@ var QrcodeCanvas = defineComponent({
|
|
|
1169
1241
|
y: imageSettings.y + margin,
|
|
1170
1242
|
width: imageSettings.w,
|
|
1171
1243
|
height: imageSettings.h,
|
|
1244
|
+
borderRadius: imageSettings.borderRadius,
|
|
1172
1245
|
};
|
|
1173
1246
|
if (imageSettings.excavation) {
|
|
1174
|
-
cells = excavateModules(cells, imageSettings.excavation);
|
|
1247
|
+
cells = excavateModules(cells, imageSettings.excavation, imageSettings.borderRadius);
|
|
1175
1248
|
}
|
|
1176
1249
|
}
|
|
1177
|
-
var devicePixelRatio = window.devicePixelRatio || 1;
|
|
1250
|
+
var devicePixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1;
|
|
1178
1251
|
var scale = (size / numCells) * devicePixelRatio;
|
|
1179
1252
|
canvas.height = canvas.width = size * devicePixelRatio;
|
|
1180
1253
|
ctx.scale(scale, scale);
|
|
@@ -1208,11 +1281,28 @@ var QrcodeCanvas = defineComponent({
|
|
|
1208
1281
|
});
|
|
1209
1282
|
}
|
|
1210
1283
|
if (showImage) {
|
|
1211
|
-
|
|
1284
|
+
var borderRadius = imageProps.borderRadius;
|
|
1285
|
+
if (borderRadius > 0) {
|
|
1286
|
+
ctx.save();
|
|
1287
|
+
ctx.beginPath();
|
|
1288
|
+
if (ctx.roundRect) {
|
|
1289
|
+
ctx.roundRect(imageProps.x, imageProps.y, imageProps.width, imageProps.height, borderRadius);
|
|
1290
|
+
}
|
|
1291
|
+
else {
|
|
1292
|
+
// Fallback for browsers without roundRect support
|
|
1293
|
+
ctx.rect(imageProps.x, imageProps.y, imageProps.width, imageProps.height);
|
|
1294
|
+
}
|
|
1295
|
+
ctx.clip();
|
|
1296
|
+
ctx.drawImage(image, imageProps.x, imageProps.y, imageProps.width, imageProps.height);
|
|
1297
|
+
ctx.restore();
|
|
1298
|
+
}
|
|
1299
|
+
else {
|
|
1300
|
+
ctx.drawImage(image, imageProps.x, imageProps.y, imageProps.width, imageProps.height);
|
|
1301
|
+
}
|
|
1212
1302
|
}
|
|
1213
1303
|
};
|
|
1214
1304
|
onMounted(generate);
|
|
1215
|
-
|
|
1305
|
+
watch(props, generate, { deep: true });
|
|
1216
1306
|
var style = ctx.attrs.style;
|
|
1217
1307
|
return function () { return h(Fragment, [
|
|
1218
1308
|
h('canvas', __assign(__assign({}, ctx.attrs), { ref: canvasEl, style: __assign(__assign({}, style), { width: "".concat(props.size, "px"), height: "".concat(props.size, "px") }) })),
|