@needle-tools/engine 4.5.7-next.029f239 → 4.5.8-next.e775d5d

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.
@@ -927,28 +927,36 @@ export async function generateQRCode(args: { domElement?: HTMLElement, text: str
927
927
  height: args.height ?? 256,
928
928
  colorDark: "#000000",
929
929
  colorLight: "#ffffff",
930
- correctLevel: QRCODE.CorrectLevel.M,
930
+ correctLevel: args.showLogo ? QRCODE.CorrectionLevel.H : QRCODE.CorrectLevel.M,
931
931
  ...args,
932
932
  });
933
933
 
934
- if (args.showLogo !== false) {
935
- const canvas = qrCode?._oDrawing?._elCanvas as HTMLCanvasElement;
936
- try {
937
- const img = await addOverlays(canvas).catch(_e => { /** ignore */ });
938
- if (img) {
939
- target.innerHTML = "";
940
- target.append(img);
941
- }
934
+ // Number of rows/columns of the generated QR code
935
+ const moduleCount = qrCode?._oQRCode.moduleCount || 0;
936
+ const canvas = qrCode?._oDrawing?._elCanvas as HTMLCanvasElement;
937
+
938
+ let sizePercentage = 0.25;
939
+ if (moduleCount < 40)
940
+ sizePercentage = Math.floor(moduleCount / 4) / moduleCount;
941
+ else
942
+ sizePercentage = Math.floor(moduleCount / 6) / moduleCount;
943
+
944
+ const paddingPercentage = Math.floor(moduleCount / 20) / moduleCount;
945
+ try {
946
+ const img = await addOverlays(canvas, { showLogo: args.showLogo, logoSize: sizePercentage, logoPadding: paddingPercentage }).catch(_e => { /** ignore */ });
947
+ if (img) {
948
+ target.innerHTML = "";
949
+ target.append(img);
942
950
  }
943
- catch { } // Ignore
944
951
  }
952
+ catch { } // Ignore
945
953
 
946
954
  if (args.showUrl !== false && args.text) {
947
955
  // Add link label below the QR code
948
956
  // Clean up the text. If it's a URL: remove the protocol, www. part, trailing slashes or trailing question marks
949
957
  const existingLabel = target.querySelector(".qr-code-link-label");
950
958
  let displayText = args.text.replace(/^(https?:\/\/)?(www\.)?/, "").replace(/\/+$/, "").replace(/\?+$/, "");
951
- displayText = "Scan to visit: " + displayText;
959
+ displayText = "Scan to visit " + displayText;
952
960
  if (existingLabel) {
953
961
  existingLabel.textContent = displayText;
954
962
  } else {
@@ -982,15 +990,21 @@ export async function generateQRCode(args: { domElement?: HTMLElement, text: str
982
990
  return target;
983
991
  }
984
992
 
985
- async function addOverlays(canvas: HTMLCanvasElement): Promise<HTMLImageElement | void> {
993
+ async function addOverlays(canvas: HTMLCanvasElement, args: { showLogo?: boolean, logoSize?: number, logoPadding?: number }): Promise<HTMLImageElement | void> {
986
994
  if (!canvas) return;
987
995
 
988
996
  // Internal settings
989
997
  const canvasPadding = 8;
990
- const shadowColor = "#00000099";
991
998
  const shadowBlur = 20;
992
- const rectanglePadding = 12;
999
+ const rectanglePadding = args.logoPadding || 1. / 32;
1000
+ // With dropshadow under the logo
1001
+ /*
1002
+ const shadowColor = "#00000099";
993
1003
  const rectangleRadius = 0.4 * 16;
1004
+ */
1005
+ // Without dropshadow under the logo
1006
+ const shadowColor = "transparent";
1007
+ const rectangleRadius = 0;
994
1008
 
995
1009
  // Draw the website's icon in the center of the QR code
996
1010
  const faviconImage = new Image();
@@ -998,14 +1012,17 @@ async function addOverlays(canvas: HTMLCanvasElement): Promise<HTMLImageElement
998
1012
  const logoSrc = element?.getAttribute("loading-logo-src") || needleLogoOnlySVG;
999
1013
  if (!logoSrc) return;
1000
1014
 
1001
- faviconImage.src = logoSrc;
1002
- const haveLogo = await new Promise((resolve, _reject) => {
1003
- faviconImage.onload = () => resolve(true);
1004
- faviconImage.onerror = (err) => {
1005
- console.error("Error loading favicon image for QR code", err);
1006
- resolve(false);
1007
- };
1008
- });
1015
+ let haveLogo = false;
1016
+ if (args.showLogo !== false) {
1017
+ faviconImage.src = logoSrc;
1018
+ haveLogo = await new Promise((resolve, _reject) => {
1019
+ faviconImage.onload = () => resolve(true);
1020
+ faviconImage.onerror = (err) => {
1021
+ console.error("Error loading favicon image for QR code", err);
1022
+ resolve(false);
1023
+ };
1024
+ });
1025
+ }
1009
1026
 
1010
1027
  // Add some padding around the canvas – we need to copy the QR code image to a larger canvas
1011
1028
  const paddedCanvas = document.createElement("canvas");
@@ -1039,20 +1056,23 @@ async function addOverlays(canvas: HTMLCanvasElement): Promise<HTMLImageElement
1039
1056
  paddedContext.globalCompositeOperation = "source-over";
1040
1057
 
1041
1058
 
1042
- let sizeX = Math.min(paddedCanvas.width, paddedCanvas.height) / 4;
1059
+ let sizeX = Math.min(canvas.width, canvas.height) * (args.logoSize || 0.25);
1043
1060
  let sizeY = sizeX;
1044
1061
 
1045
1062
  if (haveLogo) {
1046
- // get aspect of image
1063
+ // Get aspect of image
1047
1064
  const aspect = faviconImage.width / faviconImage.height;
1048
1065
  if (aspect > 1) sizeY = sizeX / aspect;
1049
1066
  else sizeX = sizeY * aspect;
1050
1067
 
1068
+ const rectanglePaddingPx = rectanglePadding * canvas.width;
1069
+
1051
1070
  // Apply padding
1052
- const sizeXPadded = sizeX + rectanglePadding;
1053
- const sizeYPadded = sizeY + rectanglePadding;
1054
- const x = (paddedCanvas.width - sizeX) / 2;
1055
- const y = (paddedCanvas.height - sizeY) / 2;
1071
+ const sizeForBackground = Math.max(sizeX, sizeY);
1072
+ const sizeXPadded = Math.round(sizeForBackground + rectanglePaddingPx);
1073
+ const sizeYPadded = Math.round(sizeForBackground + rectanglePaddingPx);
1074
+ const x = (paddedCanvas.width - sizeForBackground) / 2;
1075
+ const y = (paddedCanvas.height - sizeForBackground) / 2;
1056
1076
 
1057
1077
  // Draw shape with blurred shadow
1058
1078
  paddedContext.shadowColor = shadowColor;
@@ -1061,8 +1081,8 @@ async function addOverlays(canvas: HTMLCanvasElement): Promise<HTMLImageElement
1061
1081
  // Draw rounded rectangle with radius
1062
1082
  // Convert 0.4rem to pixels, taking DPI into account
1063
1083
  const radius = rectangleRadius;
1064
- const xPadded = x - rectanglePadding / 2;
1065
- const yPadded = y - rectanglePadding / 2;
1084
+ const xPadded = Math.round(x - rectanglePaddingPx / 2);
1085
+ const yPadded = Math.round(y - rectanglePaddingPx / 2);
1066
1086
  paddedContext.beginPath();
1067
1087
  paddedContext.moveTo(xPadded + radius, yPadded);
1068
1088
  paddedContext.lineTo(xPadded + sizeXPadded - radius, yPadded);
@@ -1080,7 +1100,9 @@ async function addOverlays(canvas: HTMLCanvasElement): Promise<HTMLImageElement
1080
1100
 
1081
1101
  // Reset shadow and draw favicon
1082
1102
  paddedContext.shadowColor = "transparent";
1083
- paddedContext.drawImage(faviconImage, x, y, sizeX, sizeY);
1103
+ const logoX = (paddedCanvas.width - sizeX) / 2;
1104
+ const logoY = (paddedCanvas.height - sizeY) / 2;
1105
+ paddedContext.drawImage(faviconImage, logoX, logoY, sizeX, sizeY);
1084
1106
  }
1085
1107
 
1086
1108
  // Replace the canvas with the padded one