qrImage.ts 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. import qrcode from "./qrcode-generator";
  2. const cache = new Map<string, string>();
  3. type QrFactory = (
  4. typeNumber: number,
  5. errorCorrectionLevel: string
  6. ) => {
  7. addData: (data: string, mode?: string) => void;
  8. make: () => void;
  9. getModuleCount: () => number;
  10. isDark: (row: number, col: number) => boolean;
  11. };
  12. const createQr = qrcode as unknown as QrFactory;
  13. /**
  14. * Integer-module PNG for Lodop ADD_PRINT_IMAGE.
  15. * Avoids Lodop QRCode raster blur and canvas anti-aliasing.
  16. */
  17. export async function qrPngDataUrl(text: string, px = 640): Promise<string> {
  18. const key = `${px}|${text}`;
  19. const hit = cache.get(key);
  20. if (hit) {
  21. return hit;
  22. }
  23. const qr = createQr(0, "L");
  24. qr.addData(text, "Byte");
  25. qr.make();
  26. const count = qr.getModuleCount();
  27. const margin = 2;
  28. const n = count + margin * 2;
  29. const cell = Math.max(8, Math.floor(px / n));
  30. const size = cell * n;
  31. const canvas = document.createElement("canvas");
  32. canvas.width = size;
  33. canvas.height = size;
  34. const ctx = canvas.getContext("2d");
  35. if (!ctx) {
  36. throw new Error("无法生成二维码画布");
  37. }
  38. ctx.imageSmoothingEnabled = false;
  39. ctx.fillStyle = "#ffffff";
  40. ctx.fillRect(0, 0, size, size);
  41. ctx.fillStyle = "#000000";
  42. for (let row = 0; row < count; row++) {
  43. for (let col = 0; col < count; col++) {
  44. if (qr.isDark(row, col)) {
  45. ctx.fillRect((col + margin) * cell, (row + margin) * cell, cell, cell);
  46. }
  47. }
  48. }
  49. const url = canvas.toDataURL("image/png");
  50. cache.set(key, url);
  51. return url;
  52. }