# 介紹好用工具：使用 Squoosh 與 Squoosh CLI 壓縮圖片

最近一直在弄客戶網站上線前的準備事項，我們在進行前端效能調校時，當然不免俗的要用 [Lighthouse](https://developer.chrome.com/docs/lighthouse/) ([GitHub](https://github.com/GoogleChrome/lighthouse)) 跑一遍，結果發現除了效能殺手 [Google Fonts](https://fonts.google.com/) 無解外，另一個主要的效能殺手就是沒有經過優化的**圖片**，畢竟圖片都是從後台上稿的，如果沒有好好的處理，是有可能會影響到用戶體驗的。今天我就來介紹一套我用很久的 [Squoosh.app](https://squoosh.app/) 網站與 Squoosh CLI 命令列工具。

![image](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/0685ec81ca4c08d9a3bc-1dc94387-ff33-40c2-a2ae-bce875d0db54.jpg)

### 簡介 Squoosh

[Squoosh](https://squoosh.app/) 是一個由 Google 開發的圖片壓縮工具，它可以幫助你快速而有效地壓縮圖片，以減小文件大小，提高網頁載入速度，同時保持圖片品質。這個工具特別適合**網頁開發者**和**設計師**，因為它提供了許多高度自定義的壓縮選項，讓你根據需要調整圖片壓縮細節。

Squoosh 提供直觀的用戶界面，使你可以輕鬆拖放圖片，也可以透過剪貼簿直接貼上圖片，然後即時預覽圖片壓縮後的效果。它支持多種常見的圖片格式，包括 JPEG、PNG、WebP、AVIF 等，並且可以在不同壓縮品質設定之間進行比較，以找到最佳的平衡點。

除了基本的壓縮功能，Squoosh 還提供了先進的選項，例如圖像縮放、旋轉、色彩配置和濾鏡應用，這些功能使你能夠在不犧牲品質品質的情況下減小文件大小。此外，Squoosh 還可以產生用於不同螢幕和設備的圖片變體，以確保最佳的視覺效果。

總之，Squoosh 是一個強大且易於使用的圖片壓縮工具，對於優化網頁性能和節省頻寬的開發者來說，它是一個不可或缺的工具。

![Squoosh](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/2dec6fc7053b01352c63-c6bb0f08-4214-4e4f-9b34-fbc26bf3697e.webp)

因為 Squoosh 本身就很容易上手，如果你想要學習如何使用，可以參考以下幾篇文章與影片：

-   文章
    -   [Google 免費圖片壓縮工具「Squoosh」，線上幫你圖片減肥](https://free.com.tw/squoosh/)
    -   [圖片壓縮 Squoosh 教學， Google 開發解決照片jpg檔案太大問題](https://turadise.com/squoosh/)
-   影片
    -   [圖片壓縮，Squoosh 超強黑科技，Google 製作免費轉換各種圖檔(強力推薦)](https://youtu.be/yAKRUNCsieY)

對了，這套 Squoosh 甚至是一套[開放原始碼](https://github.com/GoogleChromeLabs/squoosh)專案！👍

### 簡介 Squoosh CLI

有鑑於 [Squoosh](https://squoosh.app/) 的功能強大，圖片壓縮的編碼器也非常多，因此 Google 便將 Squoosh 的核心編碼器抽離出來 ([libSquoosh](https://www.npmjs.com/package/@squoosh/lib))，並且用 Node.js 與 WebAssembly 技術將它打包成一個獨立的、跨平台的命令列工具，稱為 [Squoosh CLI](https://www.npmjs.com/package/@squoosh/cli)！

不過很可惜，這個 Squoosh CLI 專案已經在 10 個月前就被 Google 放棄了 (可能跟年初的大裁員有關)：

![Squoosh CLI](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/63e7f3f9bb484a4f145f-3d64564d-5350-4b38-96d5-b2a022a2a8e1.webp)

不止這樣，我發現在 [GoogleChromeLabs/squoosh](https://github.com/GoogleChromeLabs/squoosh) 的 `dev` 分支也已經沒有這個 Squoosh CLI 原始碼了，連個 Tag 或 Branch 都不留，所以我自己 Fork 了一份在[這裡](https://github.com/doggy8088/squoosh)，你可以從我的 GitHub Repo 找到被移除的所有原始碼：[https://github.com/doggy8088/squoosh/tree/cli](https://github.com/doggy8088/squoosh/tree/cli)

由於 Squoosh CLI 本身是一個 Node.js 的命令列工具，因此你可以透過 npm 來安裝它：

```bash
npm install -g @squoosh/cli
```

Squoosh CLI 在 `Linux` 與 `macOS` 執行時都可以跑得蠻順暢的，只是執行時經常會出現一些討厭的警告訊息：

```
(node:6200) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 17 unpipe listeners added to [WriteStream]. Use emitter.setMaxListeners() to increase limit
(Use `node --trace-warnings ...` to show where the warning was created)
(node:6200) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 17 error listeners added to [WriteStream]. Use emitter.setMaxListeners() to increase limit
(node:6200) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 17 close listeners added to [WriteStream]. Use emitter.setMaxListeners() to increase limit
(node:6200) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 17 finish listeners added to [WriteStream]. Use emitter.setMaxListeners() to increase limit
```

要過濾掉這些訊息，只要設定一個 `NODE_NO_WARNINGS` 環境變數即可，如下設定：

```bash
export NODE_NO_WARNINGS=1
```

不過 Squoosh CLI 對 Windows 平台似乎不太友善，執行時會出現以下錯誤：

```bash
node:internal/deps/undici/undici:11457
    Error.captureStackTrace(err, this);
          ^

TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11457:11) {
  cause: Error: unknown scheme
      at makeNetworkError (node:internal/deps/undici/undici:6802:35)
      at schemeFetch (node:internal/deps/undici/undici:10919:18)
      at node:internal/deps/undici/undici:10792:26
      at mainFetch (node:internal/deps/undici/undici:10809:11)
      at fetching (node:internal/deps/undici/undici:10766:7)
      at fetch2 (node:internal/deps/undici/undici:10644:20)
      at Object.fetch (node:internal/deps/undici/undici:11455:18)
      at fetch (node:internal/process/pre_execution:230:25)
      at instantiateAsync (C:\Users\User\AppData\Roaming\npm\node_modules\@squoosh\cli\node_modules\@squoosh\lib\build\index.js:28:11469)
      at createWasm (C:\Users\User\AppData\Roaming\npm\node_modules\@squoosh\cli\node_modules\@squoosh\lib\build\index.js:28:12079) {
    [cause]: undefined
  }
}

Node.js v18.16.0
```

為了解決這個問題，我還特別替他開發了一套 Docker 映像檔，讓 Windows 用戶可以透過 Docker 更好的使用這套工具，你可以從 Docker Hub 的 [willh/squoosh-cli](https://hub.docker.com/r/willh/squoosh-cli) 專案找到我的映像檔，我的 [Dockerfile](https://github.com/doggy8088/docker-squoosh-cli/blob/main/Dockerfile) 與相關檔案也開源在我的 GitHub 帳號下，你可以到 [doggy8088/docker-squoosh-cli](https://github.com/doggy8088/docker-squoosh-cli) 找到我的原始碼。

基本用法如下：

1.  先拉 image 回來
    
    ```bash
    docker pull willh/squoosh-cli
    ```
    
2.  查詢基本用法
    
    這個命令有用到 `${PWD}` 變數，你只能在 PowerShell 或 Bash 環境下才能用，千萬不要用 Command Prompt (`cmd.exe`) 來執行這個命令。
    
    ```bash
    docker run --rm -it -v ${PWD}:/data willh/squoosh-cli -h
    ```
    
    基本用法如下：
    
    ```
    Usage: squoosh-cli [options] <files...>
    
    Options:
      -d, --output-dir <dir>                                 Output directory (default: ".")
      -s, --suffix <suffix>                                  Append suffix to output files (default: "")
      --max-optimizer-rounds <rounds>                        Maximum number of compressions to use for auto optimizations (default: "6")
      --optimizer-butteraugli-target <butteraugli distance>  Target Butteraugli distance for auto optimizer (default: "1.4")
      --resize [config]                                      Resize the image before compressing
      --quant [config]                                       Reduce the number of colors used (aka. paletting)
      --rotate [config]                                      Rotate image
      --mozjpeg [config]                                     Use MozJPEG to generate a .jpg file with the given configuration
      --webp [config]                                        Use WebP to generate a .webp file with the given configuration
      --avif [config]                                        Use AVIF to generate a .avif file with the given configuration
      --jxl [config]                                         Use JPEG-XL to generate a .jxl file with the given configuration
      --wp2 [config]                                         Use WebP2 to generate a .wp2 file with the given configuration
      --oxipng [config]                                      Use OxiPNG to generate a .png file with the given configuration
      -h, --help                                             display help for command
    ```
    
3.  將圖片壓縮後並轉成 WebP 格式
    
    以下命令會將 `image.png` 壓縮後 (品質維持在 80% 左右)，產生一個 `image.webp` 檔案，並且放在 `out` 子目錄下。
    
    ```bash
    docker run --rm -it -v ${PWD}:/data willh/squoosh-cli --webp '{quality:80}' -d 'out' image.png
    ```
    
    > 若沒有加上 `-d` 參數，預設會覆蓋原本的檔案。
    
    你也可以將圖片轉成 MozJPEG 格式，參數的 `[config]` 可以用很簡單的 `{}` 代表全部使用預設值：
    
    ```bash
    docker run --rm -it -v ${PWD}:/data willh/squoosh-cli --mozjpeg '{}' -d 'out' image.png
    ```
    
    我的 Docker 容器還支援用「萬用字元」來批次轉換大量圖檔：
    
    ```bash
    docker run --rm -it -v ${PWD}:/data willh/squoosh-cli --mozjpeg '{}' -d 'out' *.png
    ```
    

這套 Squoosh CLI 最大的弊病，就是完全沒有說明文件，而且 `squoosh-cli -h` 顯示的說明也非常不清楚，像是 `[config]` 要寫什麼就完全沒說，只能自己從原始碼中找答案，我有看到網路上一堆人都在瞎猜各種參數，很多都是錯誤的。

我趁著假日把所有參數都釐清了，以下的參數說明是全世界最完整的參數與選項使用說明了，我真的找不到有誰整理的比我還清楚，哈！XD

以下就是我從 [Squoosh CLI 的原始碼](https://github.com/doggy8088/squoosh/tree/cli)中抽絲剝繭出來的所有參數說明：

-   [MozJPEG](https://github.com/GoogleChromeLabs/squoosh/blob/d87eff7645c151c2f4365c2515c71f4e56ed71ca/src/features/encoders/mozJPEG/shared/meta.ts#L22-L40) (`--mozjpeg [config]`)
    
    ```javascript
    {
      quality: 75,
      baseline: false,
      arithmetic: false,
      progressive: true,
      optimize_coding: true,
      smoothing: 0,
      color_space: MozJpegColorSpace.YCbCr,
      quant_table: 3,
      trellis_multipass: false,
      trellis_opt_zero: false,
      trellis_opt_table: false,
      trellis_loops: 1,
      auto_subsample: true,
      chroma_subsample: 2,
      separate_chroma_quality: false,
      chroma_quality: 75,
    }
    ```
    
-   [WebP](https://github.com/GoogleChromeLabs/squoosh/blob/d87eff7645c151c2f4365c2515c71f4e56ed71ca/src/features/encoders/avif/shared/meta.ts#L20-L31) (`--webp [config]`)
    
    ```javascript
    {
      quality: 75,
      target_size: 0,
      target_PSNR: 0,
      method: 4,
      sns_strength: 50,
      filter_strength: 60,
      filter_sharpness: 0,
      filter_type: 1,
      partitions: 0,
      segments: 4,
      pass: 1,
      show_compressed: 0,
      preprocessing: 0,
      autofilter: 0,
      partition_limit: 0,
      alpha_compression: 1,
      alpha_filtering: 1,
      alpha_quality: 100,
      lossless: 0,
      exact: 0,
      image_hint: 0,
      emulate_jpeg_size: 0,
      thread_level: 0,
      low_memory: 0,
      near_lossless: 100,
      use_delta_palette: 0,
      use_sharp_yuv: 0,
    }
    ```
    
-   [AVIF](https://github.com/GoogleChromeLabs/squoosh/blob/d87eff7645c151c2f4365c2515c71f4e56ed71ca/src/features/encoders/jxl/shared/meta.ts#L20-L29) (`--avif [config]`)
    
    ```javascript
    {
      cqLevel: 33,
      cqAlphaLevel: -1,
      denoiseLevel: 0,
      tileColsLog2: 0,
      tileRowsLog2: 0,
      speed: 6,
      subsample: 1,
      chromaDeltaQ: false,
      sharpness: 0,
      tune: AVIFTune.auto,
    }
    ```
    
-   [JPEG-XL](https://github.com/GoogleChromeLabs/squoosh/blob/d87eff7645c151c2f4365c2515c71f4e56ed71ca/src/features/encoders/jxl/shared/meta.ts#L20-L29) (`--jxl [config]`)
    
    ```javascript
    {
      effort: 7,
      quality: 75,
      progressive: false,
      epf: -1,
      lossyPalette: false,
      decodingSpeedTier: 0,
      photonNoiseIso: 0,
      lossyModular: false,
    }
    ```
    
-   [WebP2](https://github.com/GoogleChromeLabs/squoosh/blob/d87eff7645c151c2f4365c2515c71f4e56ed71ca/src/features/encoders/wp2/shared/meta.ts#L21-L31) (`--wp2 [config]`)
    
    ```javascript
    {
      quality: 75,
      alpha_quality: 75,
      effort: 5,
      pass: 1,
      sns: 50,
      uv_mode: UVMode.UVModeAuto,
      csp_type: Csp.kYCoCg,
      error_diffusion: 0,
      use_random_matrix: false,
    }
    ```
    
-   [OxiPNG](https://github.com/GoogleChromeLabs/squoosh/blob/d87eff7645c151c2f4365c2515c71f4e56ed71ca/src/features/encoders/oxiPNG/shared/meta.ts#L22-L25) (`--oxipng [config]`)
    
    ```javascript
    {
      level: 2
    }
    ```
    
-   [Rotate](https://github.com/doggy8088/squoosh/blob/42594277fd3d1f31b60103eb05cc8df62a82fb86/libsquoosh/src/codecs.ts#L45C3-L47) (`--rotate [config]`)
    
    ```javascript
    {
      numRotations: 0
    }
    ```
    
    > Possible values: `1` for 90 degree, `2` for 180 degree, ...etc.
    
-   [Resize](https://github.com/doggy8088/squoosh/blob/42594277fd3d1f31b60103eb05cc8df62a82fb86/libsquoosh/src/codecs.ts#L32C32-L38C2) (`--resize [config]`)
    
    ```javascript
    {
      width: number,
      height: number,
      method: 'triangle' | 'catrom' | 'mitchell' | 'lanczos3',
      premultiply: true,
      linearRGB: true,
    }
    ```
    
-   [Quantize](https://github.com/doggy8088/squoosh/blob/42594277fd3d1f31b60103eb05cc8df62a82fb86/libsquoosh/src/codecs.ts#L40C1-L43C2) (`--quant [config]`)
    
    ```javascript
    {
      numColors: 256,
      dither: 1.0,
    }
    ```
    

> 注意: 並非所有 Squoosh 的功能都有對應到 Squoosh CLI 來，所以功能稍有缺陷。

### 相關連結

-   [Squoosh](https://squoosh.app/)
-   [Squoosh CLI](https://www.npmjs.com/package/@squoosh/cli) (`@squoosh/cli`)
-   [libSquoosh](https://www.npmjs.com/package/@squoosh/lib) (`@squoosh/lib`)
-   [Squoosh CLI Docker Image](https://hub.docker.com/r/willh/squoosh-cli)
-   [Squoosh CLI Docker Image Source Code](https://github.com/doggy8088/docker-squoosh-cli)
