From db685b04e52efd75213ef7540fdc0bed7dccfd9e Mon Sep 17 00:00:00 2001
From: wangrong <wangrong@shsening.com>
Date: 星期一, 26 十月 2026 21:13:37 +0800
Subject: [PATCH] 更新小程序
---
cool/utils/qrcode.ts | 199 ++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 163 insertions(+), 36 deletions(-)
diff --git a/cool/utils/qrcode.ts b/cool/utils/qrcode.ts
index 47af253..17f6237 100644
--- a/cool/utils/qrcode.ts
+++ b/cool/utils/qrcode.ts
@@ -1,39 +1,173 @@
import QRCode from "qrcode";
-const QRCODE_KEY = "recycleQrcodeBase64";
+function u32(buf: Uint8Array, offset: number, value: number) {
+ buf[offset] = (value >>> 24) & 255;
+ buf[offset + 1] = (value >>> 16) & 255;
+ buf[offset + 2] = (value >>> 8) & 255;
+ buf[offset + 3] = value & 255;
+}
-export function generateQrcode(text: string): Promise<string> {
- return new Promise((resolve) => {
- QRCode.toDataURL(
- text,
- {
- width: 300,
- margin: 2,
- },
- (err, url) => {
- if (err) {
- console.error("鉂� 浜岀淮鐮佺敓鎴愬け璐�", err);
- resolve("");
- return;
- }
- resolve(url);
- },
- );
+function crc32(data: Uint8Array) {
+ let c = 0xffffffff;
+ for (let i = 0; i < data.length; i++) {
+ c ^= data[i];
+ for (let k = 0; k < 8; k++) {
+ c = (c >>> 1) ^ (c & 1 ? 0xedb88320 : 0);
+ }
+ }
+ return (c ^ 0xffffffff) >>> 0;
+}
+
+function adler32(data: Uint8Array) {
+ let a = 1;
+ let b = 0;
+ for (let i = 0; i < data.length; i++) {
+ a = (a + data[i]) % 65521;
+ b = (b + a) % 65521;
+ }
+ return ((b << 16) | a) >>> 0;
+}
+
+function chunk(type: string, data: Uint8Array) {
+ const out = new Uint8Array(12 + data.length);
+ u32(out, 0, data.length);
+ out[4] = type.charCodeAt(0);
+ out[5] = type.charCodeAt(1);
+ out[6] = type.charCodeAt(2);
+ out[7] = type.charCodeAt(3);
+ out.set(data, 8);
+ u32(out, 8 + data.length, crc32(out.subarray(4, 8 + data.length)));
+ return out;
+}
+
+function concat(parts: Uint8Array[]) {
+ const len = parts.reduce((sum, part) => sum + part.length, 0);
+ const out = new Uint8Array(len);
+ let offset = 0;
+ for (const part of parts) {
+ out.set(part, offset);
+ offset += part.length;
+ }
+ return out;
+}
+
+function zlibStore(raw: Uint8Array) {
+ const blocks: Uint8Array[] = [];
+ let offset = 0;
+ while (offset < raw.length) {
+ const len = Math.min(65535, raw.length - offset);
+ const last = offset + len >= raw.length;
+ const block = new Uint8Array(5 + len);
+ block[0] = last ? 1 : 0;
+ block[1] = len & 255;
+ block[2] = (len >>> 8) & 255;
+ const nlen = (~len) & 0xffff;
+ block[3] = nlen & 255;
+ block[4] = (nlen >>> 8) & 255;
+ block.set(raw.subarray(offset, offset + len), 5);
+ blocks.push(block);
+ offset += len;
+ }
+ const bodyLen = blocks.reduce((sum, block) => sum + block.length, 0);
+ const out = new Uint8Array(2 + bodyLen + 4);
+ out[0] = 0x78;
+ out[1] = 0x01;
+ let cursor = 2;
+ for (const block of blocks) {
+ out.set(block, cursor);
+ cursor += block.length;
+ }
+ u32(out, cursor, adler32(raw));
+ return out;
+}
+
+function bytesToBase64(bytes: Uint8Array) {
+ const api = typeof uni === "undefined" ? undefined : uni;
+ if (api && typeof api.arrayBufferToBase64 === "function") {
+ const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
+ return api.arrayBufferToBase64(buffer as ArrayBuffer);
+ }
+ const table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ let out = "";
+ for (let i = 0; i < bytes.length; i += 3) {
+ const a = bytes[i];
+ const b = i + 1 < bytes.length ? bytes[i + 1] : 0;
+ const c = i + 2 < bytes.length ? bytes[i + 2] : 0;
+ const n = (a << 16) | (b << 8) | c;
+ out += table[(n >> 18) & 63];
+ out += table[(n >> 12) & 63];
+ out += i + 1 < bytes.length ? table[(n >> 6) & 63] : "=";
+ out += i + 2 < bytes.length ? table[n & 63] : "=";
+ }
+ return out;
+}
+
+/** 涓嶄緷璧栨祻瑙堝櫒 canvas锛岀洿鎺ョ敾鍑哄彲鍦ㄥ皬绋嬪簭 image 涓樉绀虹殑 PNG銆� */
+export function createQrPng(text: string) {
+ const qr = QRCode.create(text, { errorCorrectionLevel: "M" });
+ const modules = qr.modules;
+ const count = modules.size;
+ const margin = 4;
+ const scale = 8;
+ const size = (count + margin * 2) * scale;
+ const raw = new Uint8Array(size * (size + 1));
+ let cursor = 0;
+ for (let y = 0; y < size; y++) {
+ raw[cursor++] = 0;
+ const row = Math.floor(y / scale) - margin;
+ for (let x = 0; x < size; x++) {
+ const col = Math.floor(x / scale) - margin;
+ const dark =
+ row >= 0 && col >= 0 && row < count && col < count && !!modules.get(row, col);
+ raw[cursor++] = dark ? 0 : 255;
+ }
+ }
+ const ihdr = new Uint8Array(13);
+ u32(ihdr, 0, size);
+ u32(ihdr, 4, size);
+ ihdr[8] = 8;
+ const signature = Uint8Array.from([137, 80, 78, 71, 13, 10, 26, 10]);
+ return concat([
+ signature,
+ chunk("IHDR", ihdr),
+ chunk("IDAT", zlibStore(raw)),
+ chunk("IEND", new Uint8Array(0)),
+ ]);
+}
+
+function fileName(text: string) {
+ let hash = 0;
+ for (let i = 0; i < text.length; i++) {
+ hash = (hash * 31 + text.charCodeAt(i)) >>> 0;
+ }
+ return hash.toString(16);
+}
+
+function savePng(bytes: Uint8Array, text: string) {
+ const base64 = bytesToBase64(bytes);
+ const dataUrl = `data:image/png;base64,${base64}`;
+ const root = (globalThis as any).wx?.env?.USER_DATA_PATH;
+ if (!root || typeof uni === "undefined" || typeof uni.getFileSystemManager !== "function") {
+ return Promise.resolve(dataUrl);
+ }
+ const filePath = `${root}/recycle-qr-${fileName(text)}.png`;
+ return new Promise<string>((resolve) => {
+ uni.getFileSystemManager().writeFile({
+ filePath,
+ data: base64,
+ encoding: "base64",
+ success: () => resolve(filePath),
+ fail: () => resolve(dataUrl),
+ });
});
}
-export function generateRecycleQrcode(text: string): Promise<string> {
- return new Promise((resolve) => {
- const cached = uni.getStorageSync(QRCODE_KEY);
- if (cached) return resolve(cached);
+export function generateQrcode(text: string) {
+ return savePng(createQrPng(text), text);
+}
- generateQrcode(text).then((url) => {
- if (url) {
- uni.setStorageSync(QRCODE_KEY, url);
- }
- resolve(url);
- });
- });
+export function generateRecycleQrcode(text: string) {
+ return generateQrcode(text);
}
/**
@@ -43,10 +177,3 @@
export function clearQrcodeCache(key: string) {
uni.removeStorageSync(key);
}
-
-/**
- * 娓呴櫎鎵�鏈変簩缁寸爜缂撳瓨
- */
-export function clearAllQrcodeCache() {
- uni.clearStorageSync();
-}
\ No newline at end of file
--
Gitblit v1.9.1