---
# System prepended metadata

title: Node.js 中 DICOM 影像處理的實務取捨與方案選擇
tags: [DICOM, node.js]

---

# Node.js 中 DICOM 影像處理的實務取捨與方案選擇

在開發 PACS（Picture Archiving and Communication System）的過程中，  
「如何在 Node.js 環境下正確且穩定地處理 DICOM 影像」一直是一個極具挑戰性的問題

這篇文章記錄了筆者從專案初期開始，一路嘗試不同技術組合、踩過實務上的坑，
最終選擇解決方案的完整思考歷程

## 第一階段：DCMTK + Python 的混合方案

最早期的做法，是以 **DCMTK** 作為核心的 DICOM 工具鏈

[DCMTK](https://github.com/DCMTK/dcmtk) 是以 C++ 撰寫、歷史悠久且功能完整的 DICOM 函式庫
在實作上，筆者透過命令列方式呼叫 `dcmj2pnm`，將 DICOM 影像轉換為 PNG、JPEG 等常見格式

### 遇到的問題

第一個明顯限制是：

- `dcmj2pnm` **不支援 JPEG2000 編碼的 DICOM 影像解碼**

為了處理 JPEG2000，我只好再引入 **Python**，使用 **pydicom** 套件進行轉換

然而，問題並不只在於格式支援，而是在於**影像正確性**：

- 必須自行處理 windowing 計算  
  （Window Center、Window Width、Rescale Intercept、Rescale Slope）
- 一旦計算錯誤，輸出的影像亮度與對比就會完全失真

### 架構上的代價

這個階段的架構問題非常明顯：

- 同時依賴 **DCMTK（C++）** 與 **Python**
- Node.js 需要透過 child process 與外部程式互動
- 為了解決單一功能，引入並維護一個 Python 微服務

**結果是：功能可行，但整體架構破碎、維運成本高。**

## 第二階段：dcmjs 與 Node.js 原生解法的嘗試

[dcmjs](https://github.com/dcmjs-org/dcmjs) 可以說是近年來 nodejs 在 DICOM 處理上最偉大的進步

### 記憶體瓶頸 (致命問題)

不過筆者在深入看讀取 DICOM 檔案的程式碼發現，

```javascript
    static readFile(
        buffer,
        options = {
            ignoreErrors: false,
            untilTag: null,
            includeUntilTagValue: false,
            noCopy: false,
            forceStoreRaw: false
        }
    ) {
        // ....
    }
```

`readFile(buffer)`這個函數，它所接受的是 buffer，也就是說如果有一個 40MB 的 DICOM 檔案，你就會占用 40MB 的記憶體，這在併發處理 DICOM 影像時，非常有高機率出現 OOM 的問題

為了這個問題，筆者有透過 AI 協作做出了一個串流版本[dcmjs-stream](https://github.com/Chinlinlee/dcmjs-stream)

### 另一個限制 (Transcode)

在 PACS 應用上還有一個 transcode 的功能 (例如：將 Raw Image 的 DICOM 轉成 JPEG Image 的 DICOM)，這個功能只能使用[dcmjs-codecs](https://github.com/PantelisGeorgiadis/dcmjs-codecs)來實作，就一樣會面臨 OOM 的問題

## 最終選擇：DCM4CHEE + Java Bridge

這是筆者最後選擇的方案，因為它可以支援 DICOM 轉 JSON、各種 DICOM 的轉圖、Transcode 可以說是非常地全面，但你可能會想到，我們用的不是 node.js 嗎？這 java 的套件是要怎麼用？這時候就可以透過黑科技 [java-bridge](https://www.npmjs.com/package/java-bridge)，讓你可以在 Node.js 內去 call java 的函式

筆者也基於這個架構，實作了：
- [dcm777](https://github.com/Chinlinlee/dcm777)
    - 部分沒辦法直接在 Node.js 搭配 Java-Bridge 執行的函式抽離到 Java 去處理
- [raccoon-dcm4che-bridge](https://github.com/Chinlinlee/raccoon-dcm4che-bridge)
    - 將 dcm4che 包裝為可在 Node.js 中使用的函式庫

## 方案比較表

| 方案 | 優點 | 主要問題 |
| :--- | :--- | :---|
| DCMTK+Python | 穩定、工具成熟 | 架構破碎、需自行處理 windowing、多語言維運成本高 |
| dcmjs | 純 Node.js、生態整合佳 | 高機率遇到記憶體占用高、容易 OOM |
| DCM4CHEE + Java Bridge | 功能完整、效能穩定、臨床驗證充分 | 引入 JVM、部署複雜度提高 |