<!-- Generated by SpecStory -->

# 为什么 blurhash 生成 27 个字符 (2025-06-28 22:47:52)

_**User**_

这里 blurhash 为什么会生成 27 个字符的 string

---

_**Assistant**_

我来分析一下为什么这里生成的 blurhash 是 27 个字符的字符串。

---

<details>
            <summary>Searched web "blurhash algorithm string length calculation formula" • **5** results</summary>
        
| Title | URL |
|-------|-----|
| BlurHash | https://blurha.sh/ |
| Algorithm.md - woltapp/blurhash | https://github.com/woltapp/blurhash/blob/master/Algorithm.md |
| blurhash/Algorithm.md at master · woltapp/blurhash | https://github.com/woltapp/blurhash/blob/master/Algorithm.md |
| GitHub - woltapp/blurhash: A very compact representation of a placeholder for an image. | https://github.com/woltapp/blurhash |
| GitHub - KingsMentor/blurhash: A very compact representation of a placeholder for an image. | https://github.com/KingsMentor/blurhash |

</details>

---

<details>
            <summary>Searched web "blurhash string length formula calculation components base83" • **6** results</summary>
        
| Title | URL |
|-------|-----|
| Algorithm.md - woltapp/blurhash | https://github.com/woltapp/blurhash/blob/master/Algorithm.md |
| The Ultimate Guide to Fast-loading Websites with BlurHash | https://blog.scaleflex.com/the-ultimate-guide-to-fast-loading-websites-with-blurhash/ |
| fast_blurhash - Rust | https://docs.rs/fast-blurhash |
| blurhash/Algorithm.md at master · woltapp/blurhash | https://github.com/woltapp/blurhash/blob/master/Algorithm.md |
| GitHub - woltapp/blurhash: A very compact representation of a placeholder for an image. | https://github.com/woltapp/blurhash |
| GitHub - KingsMentor/blurhash: A very compact representation of a placeholder for an image. | https://github.com/KingsMentor/blurhash |

</details>

---

根据我搜索到的信息，我现在可以解释为什么你的 blurhash 会生成 27 个字符的字符串。

## BlurHash 字符串长度的计算原理

BlurHash 字符串的长度是由以下公式决定的：

**长度 = 1 + 1 + 4 + 2 × (xComponents × yComponents - 1)**

让我分解一下这个公式：

1. **1 位数字**：组件数量编码 `(xComponents - 1) + (yComponents - 1) × 9`
2. **1 位数字**：最大 AC 组件值
3. **4 位数字**：平均颜色（DC 组件）
4. **2 × (总组件数 - 1) 位数字**：AC 组件，每个 AC 组件用 2 个字符编码

## 你的代码中的情况

让我们看看你代码中的组件计算：

```37:44:packages/builder/src/image/blurhash.ts
    // 确保最小尺寸，避免过小的尺寸
    targetWidth = Math.max(targetWidth, 16)
    targetHeight = Math.max(targetHeight, 16)

    // 计算 blurhash 的组件数量
    // 根据图像尺寸动态调整，但限制在合理范围内
    const xComponents = Math.min(Math.max(Math.round(targetWidth / 16), 3), 9)
    const yComponents = Math.min(Math.max(Math.round(targetHeight / 16), 3), 9)
```

假设你的图像生成了 `xComponents = 4, yComponents = 4`，那么：

- 总组件数 = 4 × 4 = 16
- AC 组件数 = 16 - 1 = 15（减去 1 个 DC 组件）
- 字符串长度 = 1 + 1 + 4 + (2 × 15) = **36 个字符**

但如果是 27 个字符，那么可能的组件组合是：
- 27 = 6 + 2 × AC组件数
- AC组件数 = (27 - 6) / 2 = 10.5

这意味着实际的组件组合可能是：
- `xComponents = 4, yComponents = 3` → 总组件 = 12, AC组件 = 11 → 长度 = 6 + 22 = 28
- `xComponents = 3, yComponents = 4` → 总组件 = 12, AC组件 = 11 → 长度 = 6 + 22 = 28  
- `xComponents = 3, yComponents = 3` → 总组件 = 9, AC组件 = 8 → 长度 = 6 + 16 = 22

**最可能的情况是 `xComponents = 4, yComponents = 3` 或 `xComponents = 3, yComponents = 4`**，这会产生 28 个字符。如果你看到的是 27 个字符，可能是在某个地方有轻微的计算差异。

## 为什么使用 Base83 编码

BlurHash 使用 Base83 编码的原因：
1. **83** 是在 JSON、HTML 和 shell 中都安全使用的低 ASCII 字符的最大数量
2. **83 × 83 = 6889**，略大于 **19³ = 6859**，这使得用 2 个字符编码 3 个 AC 组件变得理想

这就是为什么你会看到相对固定长度的 blurhash 字符串的原因！

---

_**User**_

这个 blurhash的生成逻辑，在某些情况下 在我提供的代码组件中造成了报错


---

_**Assistant**_

我需要先了解一下具体的报错情况和相关代码。让我检查一下你的 blurhash 生成逻辑和使用组件。

---

<details>
            <summary>Searched codebase "Blurhash component error blurhash hash prop" • **25** results</summary>
        
| File | Lines |
|------|-------|
| `apps/web/src/pages/(debug)/blurhash.tsx` | L1-41 |
| `apps/web/src/modules/gallery/PhotoMasonryItem.tsx` | L1-31 |
| `packages/builder/src/image/blurhash.ts` | L1-55 |
| `packages/builder/src/image/blurhash.ts` | L55-76 |
| `packages/builder/src/types/photo.ts` | L150-156 |
| `apps/web/src/components/ui/photo-viewer/PhotoViewer.tsx` | L144-180 |
| `packages/builder/src/photo/cache-manager.ts` | L1-25 |
| `apps/web/src/components/ui/photo-viewer/PhotoViewer.tsx` | L1-40 |
| `apps/web/src/modules/gallery/PhotoMasonryItem.tsx` | L186-259 |
| `packages/builder/src/photo/cache-manager.ts` | L31-96 |
| `packages/builder/src/image/thumbnail.ts` | L24-88 |
| `packages/builder/src/index.ts` | L18-21 |
| `packages/builder/src/index.ts` | L25-29 |
| `apps/web/src/components/ui/photo-viewer/ProgressiveImage.tsx` | L53-95 |
| `packages/builder/src/image/thumbnail.ts` | L88-118 |
| `packages/builder/src/photo/image-pipeline.ts` | L1-27 |
| `packages/builder/package.json` | L1-25 |
| `packages/builder/src/types/photo.ts` | L43-61 |
| `packages/builder/src/image/thumbnail.ts` | L1-24 |
| `packages/builder/src/photo/index.ts` | L6-12 |
| `apps/web/src/components/ui/photo-viewer/ProgressiveImage.tsx` | L247-287 |
| `apps/web/src/components/ui/photo-viewer/SharePanel.tsx` | L1-15 |
| `apps/web/src/components/ui/photo-viewer/ExifPanel.tsx` | L476-516 |
| `apps/web/src/components/ui/photo-viewer/RawExifViewer.tsx` | L514-558 |
| `apps/web/src/components/ui/photo-viewer/ProgressiveImage.tsx` | L1-53 |

</details>

---



---

