Greasy Fork

来自缓存

Greasy Fork is available in English.

网页二维码强力识别 (Alt+点击)

按住 Alt 键点击网页上的图片即可识别二维码,完美绕过跨域限制。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         网页二维码强力识别 (Alt+点击)
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  按住 Alt 键点击网页上的图片即可识别二维码,完美绕过跨域限制。
// @author       knighttools
// @match        *://*/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jsQR.min.js
// @grant        GM_xmlhttpRequest
// @grant        GM_setClipboard
// @license      MIT
// @connect      *
// ==/UserScript==

(function() {
    'use strict';

    // 监听全局点击事件
    document.addEventListener('click', function(e) {
        // 必须按住 Alt 键,且点击的目标必须是图片
        if (e.altKey && e.target.tagName.toUpperCase() === 'IMG') {
            e.preventDefault();
            e.stopPropagation();

            const img = e.target;
            showToast('⏳ 正在解析二维码...', 'blue');

            // 尝试强制获取图片并解析 (绕过跨域)
            fetchImageAndDecode(img.src);
        }
    }, true);

    // 核心解析逻辑
    function decodeImageData(imageObj) {
        const canvas = document.createElement('canvas');
        canvas.width = imageObj.width;
        canvas.height = imageObj.height;
        const ctx = canvas.getContext('2d', { willReadFrequently: true });

        ctx.drawImage(imageObj, 0, 0, canvas.width, canvas.height);
        try {
            const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const code = jsQR(imageData.data, imageData.width, imageData.height);

            if (code && code.data) {
                // 识别成功,自动复制到剪贴板
                GM_setClipboard(code.data, "text");
                showToast(`✅ 识别成功并已复制到剪贴板!\n内容: ${code.data}`, 'green', 5000);
            } else {
                showToast('❌ 未在图片中发现二维码,或二维码太模糊。', 'orange');
            }
        } catch (err) {
            showToast('❌ 解析失败: ' + err.message, 'red');
        }
    }

    // 使用油猴的 GM_xmlhttpRequest 绕过跨域限制获取图片
    function fetchImageAndDecode(url) {
        GM_xmlhttpRequest({
            method: 'GET',
            url: url,
            responseType: 'blob',
            onload: function(response) {
                if (response.status === 200) {
                    const blob = response.response;
                    const blobUrl = URL.createObjectURL(blob);
                    const tempImg = new Image();
                    tempImg.onload = function() {
                        decodeImageData(tempImg);
                        URL.revokeObjectURL(blobUrl); // 清理内存
                    };
                    tempImg.src = blobUrl;
                } else {
                    showToast('❌ 图片加载失败,状态码: ' + response.status, 'red');
                }
            },
            onerror: function() {
                showToast('❌ 跨域请求被拦截或网络错误', 'red');
            }
        });
    }

    // 在屏幕顶部显示提示信息 (Toast)
    function showToast(text, color, duration = 3000) {
        // 移除旧的提示框
        const oldToast = document.getElementById('qr-toast-msg');
        if (oldToast) oldToast.remove();

        const toast = document.createElement('div');
        toast.id = 'qr-toast-msg';
        toast.innerText = text;

        // 颜色映射
        const colors = {
            'blue': '#3b82f6', 'green': '#10b981', 'orange': '#f59e0b', 'red': '#ef4444'
        };

        toast.style.cssText = `
            position: fixed;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: ${colors[color] || '#333'};
            color: white;
            padding: 12px 20px;
            border-radius: 8px;
            font-size: 14px;
            z-index: 2147483647;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            max-width: 80%;
            word-break: break-all;
            pointer-events: none;
            transition: opacity 0.3s;
        `;

        document.body.appendChild(toast);

        // 自动消失
        setTimeout(() => {
            toast.style.opacity = '0';
            setTimeout(() => toast.remove(), 300);
        }, duration);
    }
})();