// ==UserScript==
// @name 网页二维码识别器 - (支持 img/canvas/svg + 精准识别)
// @namespace http://tampermonkey.net/
// @version 8.0
// @description 修复 SecurityError 和 ReferenceError,支持更多元素类型,精准识别 SVG
// @author hucix
// @match *://*/*
// @grant none
// @require https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.js
// @run-at document-end
// @license MIT
// @downloadURL https://update.greasyfork.icu/scripts/553749/%E7%BD%91%E9%A1%B5%E4%BA%8C%E7%BB%B4%E7%A0%81%E8%AF%86%E5%88%AB%E5%99%A8%20-%20%EF%BC%88%E6%94%AF%E6%8C%81%20imgcanvassvg%20%2B%20%E7%B2%BE%E5%87%86%E8%AF%86%E5%88%AB%EF%BC%89.user.js
// @updateURL https://update.greasyfork.icu/scripts/553749/%E7%BD%91%E9%A1%B5%E4%BA%8C%E7%BB%B4%E7%A0%81%E8%AF%86%E5%88%AB%E5%99%A8%20-%20%EF%BC%88%E6%94%AF%E6%8C%81%20imgcanvassvg%20%2B%20%E7%B2%BE%E5%87%86%E8%AF%86%E5%88%AB%EF%BC%89.meta.js
// ==/UserScript==
(function () {
'use strict';
const HOTKEY = 'q';
let isSelecting = false;
let startX, startY;
let selectionDiv = null;
let overlay = null;
let escCloseHandler = null;
// ✅ 声明并初始化 currentResultUI
let currentResultUI = null;
function createOverlay() {
if (overlay) {
overlay.remove();
selectionDiv?.remove();
}
overlay = document.createElement('div');
overlay.style.position = 'fixed';
overlay.style.top = '0';
overlay.style.left = '0';
overlay.style.width = '100%';
overlay.style.height = '100%';
overlay.style.background = 'rgba(0,0,0,0.1)';
overlay.style.zIndex = '2147483646';
overlay.style.cursor = 'crosshair';
overlay.style.display = 'none';
document.body.appendChild(overlay);
selectionDiv = document.createElement('div');
selectionDiv.style.position = 'absolute';
selectionDiv.style.border = '2px dashed #007bff';
selectionDiv.style.background = 'rgba(0,123,255,0.1)';
selectionDiv.style.zIndex = '2147483647';
selectionDiv.style.pointerEvents = 'none';
document.body.appendChild(selectionDiv);
}
function resetState() {
isSelecting = false;
if (overlay) {
overlay.style.display = 'none';
document.body.style.userSelect = '';
}
document.removeEventListener('keydown', escHandler);
overlay?.removeEventListener('mousedown', startSelect);
overlay?.removeEventListener('mousemove', updateSelect);
overlay?.removeEventListener('mouseup', endSelect);
createOverlay();
}
function escHandler(e) {
if (e.key === 'Escape') resetState();
}
function startSelect(e) {
if (!isSelecting) return;
startX = e.pageX;
startY = e.pageY;
selectionDiv.style.display = 'block';
selectionDiv.style.left = startX + 'px';
selectionDiv.style.top = startY + 'px';
selectionDiv.style.width = '0';
selectionDiv.style.height = '0';
}
function updateSelect(e) {
if (!isSelecting || selectionDiv.style.display !== 'block') return;
const x = Math.min(startX, e.pageX);
const y = Math.min(startY, e.pageY);
const w = Math.abs(e.pageX - startX);
const h = Math.abs(e.pageY - startY);
selectionDiv.style.left = x + 'px';
selectionDiv.style.top = y + 'px';
selectionDiv.style.width = w + 'px';
selectionDiv.style.height = h + 'px';
}
// 检查两个矩形是否相交
function rectsIntersect(r1, r2) {
return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top);
}
async function recognizeQR(x, y, width, height) {
const selectionRect = { left: x, top: y, right: x + width, bottom: y + height };
let found = false;
// 1. 尝试识别
元素
const images = Array.from(document.querySelectorAll('img'));
for (const img of images) {
if (!img.complete || img.naturalWidth === 0) continue;
const imgRect = img.getBoundingClientRect();
const imgPageRect = {
left: imgRect.left + window.scrollX,
top: imgRect.top + window.scrollY,
right: imgRect.right + window.scrollX,
bottom: imgRect.bottom + window.scrollY
};
if (rectsIntersect(selectionRect, imgPageRect)) {
try {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const code = jsQR(imageData.data, canvas.width, canvas.height);
if (code) {
showResult(code.data);
found = true;
break;
}
} catch (e) {
console.warn('跳过受 CORS 保护的图片:', img.src);
}
}
}
// 2. 如果没有找到,尝试识别