重现 Chrome 经典:用 WebAssembly 打造像素级完美的二维码生成器扩展

引言

还记得 Chrome 浏览器曾经内置的二维码生成器功能吗?那个简洁优雅的界面,带有标志性 Chrome 恐龙图标的二维码,曾经是我们分享网页链接的得力助手。虽然 Google 在某个版本中移除了这个功能,但今天我要介绍一个令人兴奋的开源项目------它不仅重新带回了这个功能,更是在技术实现上达到了像素级的完美复刻。

这个名为"Add QR Code Generator Icon Back To Address Bar"的 Chrome 扩展,使用 WebAssembly 技术完美复现了 Chromium 的原生二维码生成算法,让我们能够重新享受这个经典功能。

项目概览

核心特性

  • Chromium 风格二维码:与 Chrome 原生实现完全相同的视觉外观
  • Chrome 恐龙中心图案:经典的 Chrome 恐龙图标作为二维码中心图案
  • 即时生成:自动为当前页面 URL 生成二维码
  • 自定义文本支持:为任何文本或 URL 创建二维码
  • 一键复制与下载:支持高质量 PNG 图像的复制和下载

技术栈

这个项目采用了现代化的技术栈:

json 复制代码
{
  "框架": "WXT - 现代 Web 扩展框架",
  "前端": "React 19 + TypeScript",
  "样式": "Tailwind CSS 4.0 + Radix UI 组件",
  "二维码生成": "WebAssembly 模块",
  "构建系统": "Vite + Rollup",
  "包管理器": "pnpm"
}

技术深度解析

1. WebAssembly 驱动的二维码生成

项目的核心亮点是使用 WebAssembly 模块来复制 Chrome 的原生二维码生成算法。让我们看看加载器的实现:

typescript 复制代码
// src/lib/wasm-loader.ts
export interface WasmQRGenerator {
  QuietZone: {
    WillBeAddedByClient: number
    Included: number
  }
  CenterImage: {
    Dino: number
    None: number
  }
  ModuleStyle: {
    Circles: number    // 圆形模块
    Squares: number    // 方形模块
  }
  LocatorStyle: {
    Rounded: number    // 圆角定位符
    Square: number     // 方形定位符
  }
  generate_qr_code_with_options: (
    text: string,
    moduleStyle: number,
    locatorStyle: number,
    centerImage: number,
    quietZone: number
  ) => QRCodeResult
}

2. 精确的常量定义

为了确保与 Chromium 完全一致,项目定义了精确的常量:

typescript 复制代码
// src/hooks/use-qrcode.ts
const MODULE_SIZE_PIXELS = 10        // 每个模块 10 像素
const DINO_TILE_SIZE_PIXELS = 4      // 恐龙图块 4 像素
const LOCATOR_SIZE_MODULES = 7       // 定位符 7x7 模块
const QUIET_ZONE_SIZE_PIXELS = MODULE_SIZE_PIXELS * 4  // 40 像素边距
const MAX_INPUT_LENGTH = 2000        // 最大输入长度

3. Chrome 恐龙图案的像素级复制

最令人印象深刻的是,项目直接从 Chromium 源码复制了恐龙图案的像素数据:

typescript 复制代码
// 恐龙尺寸定义
const kDinoWidth = 20
const kDinoHeight = 22
const kDinoHeadHeight = 8
const kDinoBodyHeight = 14

// 恐龙头部像素数据(面向右侧)- 直接从 Chromium 复制
const kDinoHeadRight = [
  0b00000000, 0b00011111, 0b11100000,
  0b00000000, 0b00111111, 0b11110000,
  0b00000000, 0b00110111, 0b11110000,
  // ... 更多像素数据
]

// 恐龙身体像素数据
const kDinoBody = [
  0b10000000, 0b01111100, 0b00000000,
  0b10000001, 0b11111100, 0b00000000,
  // ... 更多像素数据
]

4. 自定义 Hook:useQRCode

项目使用 React Hook 模式封装二维码生成逻辑:

typescript 复制代码
export const useQRCode = (): [QRCodeState, QRCodeActions] => {
  const [state, setState] = useState<QRCodeState>({
    isLoading: false,
    error: null,
    qrData: null,
    qrSize: 0,
    originalSize: 0
  })

  const generateQRCode = useCallback(async (inputText: string) => {
    // 验证输入长度
    if (inputText.length > MAX_INPUT_LENGTH) {
      setState(prev => ({
        ...prev,
        error: `Input is too long. Please shorten the text to ${MAX_INPUT_LENGTH} characters or less.`
      }))
      return
    }

    // 调用 WASM 模块生成二维码
    const result = wasmModuleRef.current.generate_qr_code_with_options(
      inputText,
      wasmModuleRef.current.ModuleStyle.Circles,     // 圆形数据模块
      wasmModuleRef.current.LocatorStyle.Rounded,    // 圆角定位符
      wasmModuleRef.current.CenterImage.Dino,        // 恐龙中心图案
      wasmModuleRef.current.QuietZone.WillBeAddedByClient
    )
  }, [])

  return [state, { generateQRCode, copyQRCode, downloadQRCode, clearError }]
}

5. 画布渲染:精确复制 Chromium 的绘制算法

圆角定位符绘制

typescript 复制代码
const drawLocators = (
  ctx: CanvasRenderingContext2D,
  dataSize: { width: number; height: number },
  paintForeground: { color: string },
  paintBackground: { color: string },
  margin: number,
  modulePixelSize: number
) => {
  const chromiumModuleSize = 10
  const scaleFactor = modulePixelSize / chromiumModuleSize
  const radius = 10 * scaleFactor

  const drawOneLocator = (leftXModules: number, topYModules: number) => {
    // 最外层正方形,7x7 模块
    let leftXPixels = leftXModules * modulePixelSize
    let topYPixels = topYModules * modulePixelSize
    let dimPixels = modulePixelSize * LOCATOR_SIZE_MODULES

    drawRoundRect(ctx, margin + leftXPixels, margin + topYPixels,
                  dimPixels, dimPixels, radius, paintForeground.color)

    // 中间正方形,5x5 模块
    leftXPixels += modulePixelSize
    topYPixels += modulePixelSize
    dimPixels -= 2 * modulePixelSize

    drawRoundRect(ctx, margin + leftXPixels, margin + topYPixels,
                  dimPixels, dimPixels, radius, paintBackground.color)

    // 内层正方形,3x3 模块
    leftXPixels += modulePixelSize
    topYPixels += modulePixelSize
    dimPixels -= 2 * modulePixelSize

    drawRoundRect(ctx, margin + leftXPixels, margin + topYPixels,
                  dimPixels, dimPixels, radius, paintForeground.color)
  }

  // 绘制三个定位符:左上、右上、左下
  drawOneLocator(0, 0)
  drawOneLocator(dataSize.width - LOCATOR_SIZE_MODULES, 0)
  drawOneLocator(0, dataSize.height - LOCATOR_SIZE_MODULES)
}

恐龙图案的像素级绘制

typescript 复制代码
const drawDinoPixelByPixel = (
  ctx: CanvasRenderingContext2D,
  destX: number,
  destY: number,
  destWidth: number,
  destHeight: number
) => {
  const scaleX = destWidth / kDinoWidth
  const scaleY = destHeight / kDinoHeight

  ctx.fillStyle = moduleColor

  const drawPixelData = (srcArray: number[], srcNumRows: number, startRow: number) => {
    for (let row = 0; row < srcNumRows; row++) {
      for (let bit = 0; bit < kDinoWidth; bit++) {
        const byteIndex = row * kDinoWidthBytes + Math.floor(bit / 8)
        const bitIndex = 7 - (bit % 8)

        if (srcArray[byteIndex] & (1 << bitIndex)) {
          const pixelX = destX + bit * scaleX
          const pixelY = destY + (startRow + row) * scaleY
          ctx.fillRect(pixelX, pixelY, scaleX, scaleY)
        }
      }
    }
  }

  // 绘制恐龙头部和身体
  drawPixelData(kDinoHeadRight, kDinoHeadHeight, 0)
  drawPixelData(kDinoBody, kDinoBodyHeight, kDinoHeadHeight)
}

6. 用户界面:复制 Chrome 的设计语言

主界面组件完美复制了 Chrome 的设计风格:

tsx 复制代码
// src/popup/App.tsx
function App() {
  const [qrState, qrActions] = useQRCode()
  const [inputValue, setInputValue] = useState('')

  // 自动获取当前标签页 URL
  useEffect(() => {
    if (typeof window !== 'undefined' && window.chrome?.tabs) {
      chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
        if (tabs[0]?.url) {
          setInputValue(tabs[0].url)
        }
      })
    }
  }, [])

  // 智能文件名生成
  const handleDownload = () => {
    if (qrState.qrData) {
      let filename = 'qrcode_chrome.png'
      try {
        const url = new URL(inputValue)
        if (url.hostname && !/^\d{1,3}(\.\d{1,3}){3}$/.test(url.hostname)) {
          const safeHostname = url.hostname.replace(/[^a-zA-Z0-9.-]/g, '_')
          filename = `qrcode_${safeHostname}.png`
        }
      } catch (e) {
        // 使用默认文件名
      }
      qrActions.downloadQRCode(filename)
    }
  }

  return (
    <div className="chromium-bubble flex w-80 flex-col p-0 leading-5">
      {/* 标题栏 - 匹配 Chromium 样式 */}
      <div className="chromium-title-bar flex min-h-10 items-center justify-between">
        <h2 className="chromium-title text-sm font-medium">Scan QR Code</h2>
        <button onClick={() => window.close()}>×</button>
      </div>

      {/* 二维码显示区域 - 精确的 240px 尺寸 */}
      <div className="chromium-qr-container relative flex items-center justify-center">
        <QRCodeCanvas qrData={qrData} qrSize={qrSize} originalSize={originalSize} />
      </div>

      {/* 输入框 - 匹配 Chromium 的可访问性标准 */}
      <Input
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        aria-label="URL or text to encode"
        placeholder="Enter URL or text"
        maxLength={2000}
      />

      {/* 按钮容器 */}
      <div className="chromium-button-container flex items-center gap-2">
        <Button onClick={handleCopy}>Copy</Button>
        <Button onClick={handleDownload}>Download</Button>
      </div>
    </div>
  )
}

工作原理图解

scss 复制代码
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   用户输入URL    │───▶│  WASM二维码生成   │───▶│   Canvas渲染    │
│   或文本内容     │    │                  │    │                 │
└─────────────────┘    └──────────────────┘    └─────────────────┘
                                │                        │
                                ▼                        ▼
                       ┌──────────────────┐    ┌─────────────────┐
                       │  二维码数据       │    │  绘制定位符      │
                       │  (Uint8Array)    │    │  (圆角方形)      │
                       └──────────────────┘    └─────────────────┘
                                                        │
                                                        ▼
                                               ┌─────────────────┐
                                               │  绘制数据模块    │
                                               │  (圆形)         │
                                               └─────────────────┘
                                                        │
                                                        ▼
                                               ┌─────────────────┐
                                               │  绘制恐龙图案    │
                                               │  (像素级精确)    │
                                               └─────────────────┘

安装和使用

从 Chrome 网上应用店安装

bash 复制代码
# 直接访问Chrome网上应用店
https://chromewebstore.google.com/detail/add-qr-code-generator-ico/kacblhilkacgfnkjfodalohcnllcgmjd

开发环境搭建

bash 复制代码
# 克隆仓库
git clone https://github.com/chromium-style-qrcode/add-qrcode-generator-icon-back-to-address-bar.git
cd add-qrcode-generator-icon-back-to-address-bar

# 安装依赖(需要Node.js ≥ 24.3.0)
pnpm install

# 启动开发服务器
pnpm dev

# 生产环境构建
pnpm build

# 创建分发压缩包
pnpm zip

加载到 Chrome

  1. 打开 Chrome 并导航到 chrome://extensions/
  2. 在右上角启用"开发者模式"
  3. 点击"加载已解压的扩展程序"
  4. 选择 .output/chrome-mv3 文件夹

技术创新点

1. WebAssembly 的高性能应用

通过 WebAssembly 模块,项目实现了:

  • 高性能:接近原生的二维码生成速度
  • 精确性:与 Chromium 算法完全一致的结果
  • 跨平台:在所有支持 WebAssembly 的浏览器中运行

2. 像素级完美的恐龙图案

项目直接从 Chromium 源码提取恐龙图案的二进制数据,确保了:

  • 100% 相同的视觉效果
  • 精确的像素对齐
  • 正确的比例缩放

3. 现代 React 架构

使用 React 19 和 TypeScript 构建,提供了:

  • 类型安全:完整的 TypeScript 类型定义
  • 组件化设计:可复用的 UI 组件
  • 状态管理:清晰的 Hook 模式

4. Chromium 风格的用户界面

通过 Tailwind CSS 精心重现了 Chrome 的设计语言:

  • 精确的尺寸:240px 的二维码显示区域
  • 原生的颜色方案:与 Chrome 一致的颜色
  • 可访问性支持:完整的 ARIA 标签和键盘导航

性能优化策略

1. 防抖输入处理

typescript 复制代码
useEffect(() => {
  const timer = setTimeout(() => {
    qrActions.generateQRCode(inputValue)
  }, 300) // 300ms 防抖

  return () => clearTimeout(timer)
}, [inputValue, qrActions])

2. Canvas 优化

typescript 复制代码
// 启用高质量缩放
ctx.imageSmoothingEnabled = false
ctx.imageSmoothingQuality = 'high'

// 使用离屏 Canvas 进行复制和下载
const clipboardCanvas = document.createElement('canvas')

3. 内存管理

typescript 复制代码
// 及时清理 WASM 模块资源
const wasmModuleRef = useRef<WasmQRGenerator>(null)

useEffect(() => {
  return () => {
    // 组件卸载时清理资源
    if (wasmModuleRef.current) {
      // 清理逻辑
    }
  }
}, [])

项目意义与价值

这个项目不仅仅是一个简单的 Chrome 扩展,它代表了:

  1. 开源精神的体现:通过开源让优秀功能得以延续
  2. 技术精益求精:对细节的极致追求和像素级的完美重现
  3. 现代化技术栈的应用:WebAssembly、React 19、TypeScript 等前沿技术的综合运用
  4. 用户体验的重视:完整的可访问性支持和流畅的交互体验

总结

"Add QR Code Generator Icon Back To Address Bar"项目是一个技术与情怀并重的优秀作品。它不仅成功地重现了 Chrome 经典的二维码生成功能,更在技术实现上达到了令人赞叹的精确度。

通过 WebAssembly 技术实现的高性能二维码生成,像素级完美的恐龙图案复制,以及现代化的 React 架构,这个项目为我们展示了如何用最新的技术栈重现经典功能的完美范例。

对于开发者而言,这个项目提供了丰富的学习价值:从 WebAssembly 的实际应用,到 Canvas 的高级渲染技巧,从 React Hook 的优雅设计,到 Chrome 扩展的开发最佳实践。

如果你也怀念 Chrome 的经典二维码功能,或者对前端技术的深度应用感兴趣,不妨尝试这个扩展,或者深入研究其源码。相信你会像我一样,被其技术实现的精妙和对细节的极致追求所震撼。


项目地址github.com/chromium-st...

Chrome 网上应用店chromewebstore.google.com/detail/add-...

许可证:MIT License

相关推荐
是晓晓吖6 小时前
源网站数据采集方案之解析DOM(四)
前端·chrome
你怎么知道我是队长19 小时前
python-enumrate函数
开发语言·chrome·python
Xi-Xu1 天前
隆重介绍 Xget for Chrome:您的终极下载加速器
前端·网络·chrome·经验分享·github
守城小轩1 天前
Chromium 136 编译指南 - Android 篇:获取源码(五)
chrome·指纹浏览器·浏览器开发·手机浏览器
angen20181 天前
Ruby如何采集直播数据源地址
前端·chrome
ricky_fan1 天前
解决bash终端的路径名称乱码问题
开发语言·chrome·vscode·bash
望获linux1 天前
【实时Linux实战系列】多核同步与锁相(Clock Sync)技术
linux·前端·javascript·chrome·操作系统·嵌入式软件·软件
土豆12502 天前
提升CSS开发效率的必备Chrome插件
css·chrome
vvw&4 天前
Linux 中的 .bashrc 是什么?配置详解
linux·运维·服务器·chrome·后端·ubuntu·centos