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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * qrcode.vue v3.6.0
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 ops = [];
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
- ops.push("M".concat(start + margin, " ").concat(y + margin, "h").concat(x - start, "v1H").concat(start + margin, "z"));
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
- ops.push("M".concat(x + margin, ",").concat(y + margin, " h1v1H").concat(x + margin, "z"));
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
- ops.push("M".concat(start + margin, ",").concat(y + margin, " h").concat(x + 1 - start, "v1H").concat(start + margin, "z"));
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 ops.join('');
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 * 0.1);
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
- return modules.slice().map(function (row, y) {
990
- if (y < excavation.y || y >= excavation.y + excavation.h) {
991
- return row;
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 (x < excavation.x || x >= excavation.x + excavation.w) {
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: 100,
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: 0,
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: 'qr-gradient' }, gradientProps), [
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.onUpdated(generate);
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 ? 'url(#qr-gradient)' : props.foreground,
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
- ctx.drawImage(image, imageProps.x, imageProps.y, imageProps.width, imageProps.height);
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.onUpdated(generate);
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") }) })),
@@ -1,10 +1,10 @@
1
1
  /*!
2
- * qrcode.vue v3.6.0
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, onUpdated, h, onMounted, Fragment } from 'vue';
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 ops = [];
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
- ops.push("M".concat(start + margin, " ").concat(y + margin, "h").concat(x - start, "v1H").concat(start + margin, "z"));
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
- ops.push("M".concat(x + margin, ",").concat(y + margin, " h1v1H").concat(x + margin, "z"));
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
- ops.push("M".concat(start + margin, ",").concat(y + margin, " h").concat(x + 1 - start, "v1H").concat(start + margin, "z"));
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 ops.join('');
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 * 0.1);
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
- return modules.slice().map(function (row, y) {
986
- if (y < excavation.y || y >= excavation.y + excavation.h) {
987
- return row;
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 (x < excavation.x || x >= excavation.x + excavation.w) {
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: 100,
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: 0,
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: 'qr-gradient' }, gradientProps), [
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
- onUpdated(generate);
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 ? 'url(#qr-gradient)' : props.foreground,
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
- ctx.drawImage(image, imageProps.x, imageProps.y, imageProps.width, imageProps.height);
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
- onUpdated(generate);
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") }) })),
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@rstest/core").RstestConfig;
2
+ export default _default;
@@ -9,6 +9,7 @@ export type ImageSettings = {
9
9
  height: number;
10
10
  width: number;
11
11
  excavate?: boolean;
12
+ borderRadius?: number;
12
13
  };
13
14
  export declare const QrcodeSvg: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
14
15
  value: {