# DICOM 閱片器 在瀏覽器裡開啟 .dcm 影像

CT、MR、X 光和超音波，連窗寬窗位、頭資訊和測量一起。

> 在瀏覽器裡開啟 CT、MR、X 光和超音波影像。調窗寬窗位，翻整套序列，按毫米測量，讀遍每一個 DICOM 標籤，還能看清這個檔案裡究竟什麼在指認病人。什麼都不會上傳。

本頁是一個完全在你的瀏覽器裡執行的互動式工具，地址是 https://abox.tools/zh-TW/dicom-viewer/。你交給它的任何內容都不會被上傳。下面是這個頁面用文字對該工具的全部說明；要使用它，請開啟這個地址。

## 你的影像**不會上傳**。這裡根本沒有伺服器。

影像的讀取和解碼全由你自己的瀏覽器完成，頭資訊、畫素、窗寬窗位、測量，都是。這一頁的另一頭根本沒有伺服器可以接收診療資訊，這裡的任何一段程式碼想送也送不出去。而且關於這個檔案的一切都不會告訴任何人，病人的姓名不會，檢查內容不會，檔名也不會。

- ✗ 不上傳
- ✗ 不用註冊
- ✓ 斷網也能用
- ✓ 開源
- ✓ 檔案留在你的裝置上

## 怎麼開啟一個 DICOM 檔案

1. **選檔案。** 一個 `.dcm` 檔案，或者光碟上的整個資料夾。一次 CT 或者 MR 是一層一個檔案，把它們一起拖進來才是把序列重新拼起來的辦法。檔案由瀏覽器直接從你的硬碟讀取，這期間什麼都不會送去任何地方。
2. **選序列。** 一次檢查通常有好幾套，先是定位像，然後是每一次採集。每一套都按裝置拍攝的順序疊好，而這個順序不是從編號來的，是從每一層在身體裡的位置算出來的。編號不一定總朝同一個方向排。
3. **調窗。** 這是讓影像變得可讀的那個操作，也是影像編輯軟體沒有的那個。在圖上橫著拖，窗就變寬，上下拖，窗心就移動。CT 還可以直接選帶名字的窗，肺窗、骨窗、腦窗、軟組織窗。CT 的單位在全世界任何一臺機器上都一樣。
4. **翻層。** 圖下面那條滑桿在層與層之間移動，在圖上點一下之後，方向鍵也是同樣的效果。多幀檔案，比如超音波的一段迴圈、一次血管造影，用旁邊那個按鈕播放。
5. **量點什麼。** 切到測量，拉一條線。檔案寫了畫素間距的，答案就是毫米，而且不是正方形的畫素也會照顧到。檔案沒寫的，答案就是畫素數，並且會明說，不會自己編一個比例出來。
6. **讀頭資訊。** 檔案裡的每一個元素，連編號、標準給它的名字和裡面的內容一起，都可以搜尋。它上面是這一份檔案裡究竟什麼在指認病人的清單，而那遠不止一個姓名。
7. **把需要的帶走。** 螢幕上那一幀存成 PNG，保留你調好的窗，上面不燒任何字；或者把整份頭資訊存成純文字。兩樣都是在這一頁裡用已經在頁面上的東西拼出來的。

## 說得更細的版本

[怎麼開啟一個 DICOM 檔案，以及裡面有什麼](https://abox.tools/zh-TW/guides/open-a-dicom-file/): 醫院給的光碟裡都有什麼，檔案為什麼沒有字尾，怎麼在瀏覽器裡開啟一份 .dcm 影像，窗寬窗位到底在做什麼，以及一份影像除了影像之外還帶著關於病人的哪些東西。

## 工具箱裡還有

- [圖片轉 ICO](https://abox.tools/zh-TW/image-to-ico/): 進去一張圖，出來的是瀏覽器、Windows 和 Mac 各自要的每一個尺寸。
- [圖片轉 Data URI](https://abox.tools/zh-TW/image-to-data-uri/): 整張圖變成一行文字，直接貼進 CSS 或者 HTML。
- [SVG 轉圖片](https://abox.tools/zh-TW/svg-to-image/): 說個尺寸。向量圖本來就沒有尺寸可丟。
- [圖片轉 SVG](https://abox.tools/zh-TW/image-to-svg/): 一個形狀，一條輪廓。不該有的東西，點一下就好。

## 常見問題

### 我的影像會被上傳嗎？

不會。檔案的讀取、解碼和繪製全都由你自己的瀏覽器在你自己的硬體上完成。這個工具根本沒有伺服器那一半，頁面的 `Content-Security-Policy` 裡寫著它能聯絡的每一個地址，沒有一個屬於本站。把網線拔了，它照樣開啟影像。 \
\
這件事在這裡比在本站任何一頁都重要。DICOM 檔案的頭資訊裡帶著病人的姓名、出生日期和住院號，所以把它傳到某個閱片器，等於把一份病歷交給陌生人，而不是一張圖片。

### 它能開啟哪些 DICOM 檔案？

三種基本 transfer syntax 的未壓縮檔案，也就是 implicit 和 explicit littleendian，加上那個已經廢止的 big endian。此外還有 deflated、RLE Lossless、baseline JPEG 和 JPEG Lossless，醫院光碟上的 CT 和 MR 檢查大多用的是最後這種。 \
\
它解不了 JPEG 2000、JPEG-LS，也解不了影片用的 MPEG 和 HEVC 那幾種。那些需要好幾 MB 的編譯庫，而一個用到時才去下載的頁面，就不再是斷網能用的頁面了。這類檔案照樣打得開，整份頭資訊會讀出來顯示，影像的位置換成一行字寫明是哪個編解碼器，而不是一個什麼都說不出的破圖示。

### 什麼是「窗寬窗位」，為什麼需要它？

一層 CT 裡大約有四千個不同的數值，你的螢幕只能顯示兩百五十六級灰。總得有什麼來決定這四千裡哪一段吃下全部這兩百五十六級，這個選擇就是**窗**。比它低的全黑，比它高的全白，中間那一段鋪滿灰階。 \
\
同一個檔案在兩種設定下看起來像兩次檢查，原因就在這裡，肺和骨沒法同時看清也是。CT 上的數值是亨氏單位，是絕對定義的，水是 0，空氣是 −1000，全世界每一臺 CT 都如此。所以這一頁上那些帶名字的窗，和放射科醫生在工作站上用的是同一批數字。MR 和超音波沒有這樣的標度，開啟時用的是檔案自己要求的那個窗。

### 為什麼它說我的測量結果是畫素？

因為那個檔案沒寫一個畫素有多大。寫這個的是 Pixel Spacing (0028,0030)，單位是毫米，而很多超音波影像、掃描檔和 secondary capture 乾脆就沒有這一項。 \
\
有的時候，測量結果是毫米，而且每個方向按自己的間距算，這在畫素不是正方形的圖上很要緊。沒有的時候，老實的答案就是畫素數，它也照實說，而不是挑一個比例把結果當成長度端出來。

### 它把我的資料夾分成了好幾套序列，為什麼？

因為裡面本來就是這樣。一次檢查由若干序列組成，先是定位像，然後是每一次採集或者重建，每一個檔案都在 Series Instance UID (0020,000E) 裡寫明自己屬於哪一套。那個下拉選單是照這個建的，不是照資料夾建的，資料夾裡通常就是一堆名字混在一起。 \
\
在一套序列內部，層的順序按每一層在身體裡的位置排，這個位置來自 Image Position 和 Image Orientation。Instance Number 是最順手的那把鑰匙，但它是備選而不是首選。它由寫這些檔案的東西分配，沒有理由跟病人的方向一致。

### 「什麼在指認病人」這份清單是什麼意思？

是你檔案裡每一個點名影像中那個人、或者縮小他可能是誰的欄位，都在你的機器上從這一個檔案裡讀出來。清單的依據是 DICOM 標準的 PS3.15，也就是規定一份資料集要能被稱作去標識化之前，必須先去掉什麼的那一部分。 \
\
它之所以在這裡，是因為人們弄錯的不是「影像裡有個姓名」這件事，而是裡面還有多少別的。出生日期、檢查號、開單醫生、機構、裝置序列號，還有檢查的那幾個 UID，而 UID 是回到出片檔案庫的完美鑰匙。一份只抹掉姓名的影像並不匿名。 \
\
這個工具只給你看。它什麼都不寫，什麼都不改，所以它也拿不掉其中任何一項。

### 它能把影像匿名化嗎？

不能，而且它故意不裝作能。這一頁只讀，裡面沒有一行程式碼會寫 DICOM 檔案。它做的是告訴你你那份檔案裡到底有什麼，而這恰恰是難查清、又常被弄錯的那一半。 \
\
真要把這些標識拿掉，是另一件門檻高得多的工作。它得在不碰畫素的前提下重寫檔案，把整次檢查裡的 UID 一致地替換掉，還得在某些裝置偷偷藏了第二份姓名的私有元素上判斷正確。那件事寫在本站的路線圖裡，不是貼在閱片器上順手做的。

### 沒有 .dcm 字尾的檔案，或者壞掉的檔案，它打得開嗎？

都打得開。字尾根本不看，看的是檔案本身。有些資料集寫的時候沒有那慣常的 128 位元組前導，直接從網路上取下來的影像就是這個樣子，那就從第一個元素推斷出它的編碼方式來讀，頁面也會寫明它是這麼做的。 \
\
中途斷掉的檔案，讀到哪裡算哪裡。損壞之前的部分全部顯示出來，並註明它停在第幾個位元組。恰恰是這種時候最需要閱片器，所以為了最後十二個位元組就把整個檔案扔掉，那才是錯的做法。

### 這是診斷用的閱片器嗎？

不是。它不是醫療器械，沒有經過任何監管評估，這裡的任何東西都不該拿來做臨床判斷。你的螢幕沒有校準，瀏覽器不是經過驗證的渲染鏈路，這兩件事都不是一個網頁從內部能解決的。 \
\
但人們開啟影像的其他所有理由，它都夠用：看看光碟裡有什麼，取一層放進課件或者論文，讀頭資訊，弄清另一個程式為什麼拒收這個檔案，以及看清一份影像究竟帶著關於那個人的多少東西。

### 它會改我的檔案嗎？

不會。這個工具只讀。沒有輸出檔案，沒有重新編碼，這裡也沒有一個按鈕會寫出 DICOM。你能下載的是螢幕上那一幀的 PNG，和頭資訊的純文字副本。原件原封不動地留在你的硬碟上。

### 免費嗎？要註冊嗎？

免費，沒有帳號，不用登入，也沒有試用期。檔案多大、開多少個都沒有限制，除了你自己機器的記憶體。本站靠廣告養活，廣告那邊拿不到關於你檔案的任何東西。

### 斷網能用嗎？

能。把頁面載入一次，然後斷網，它照樣能用。這也是證明什麼都沒被上傳的最簡單辦法。要是有個工具把你的影像送出去讓別人畫，拔掉網線的那一刻它就停了。

## 這條隱私承諾怎麼核實

- **你的影像沒有地方可去。** Content-Security-Policy 裡寫著這一頁能聯絡的每一個地址，沒有一個屬於本站。這裡沒有一個能收集你檔案的介面，就算有，程式碼裡也沒有任何東西會把它送出去。以前這裡寫的是 `connect-src 'none'`，那是徹底關死的。加廣告讓我們失去了它，把這件事說出來也是約定的一部分。
- **這件事在這裡比在別的頁面上更重。** DICOM 檔案不是加了後設資料的圖片，是裝著圖片的病歷。病人的姓名、出生日期、住院號、檢查號、開單醫生、機構名稱、裝置序列號，全都是頭資訊裡的欄位，檔案走到哪裡它們就跟到哪裡。為了看一眼把它傳到某個網站，等於把這些全部交給那個網站的運營方。這一頁存在的意義，正是不做這件事。
- **讀它的部分就是本儲存庫裡的十四個檔案。** 這裡沒有一處用到從別處取來的庫。`src/dicom.js` 走遍檔案，`src/dictionary.js` 知道標籤叫什麼，`src/pixels.js` 把位元組還原成測量值，`src/rle.js` 和 `src/jpeg-lossless.js` 展開這一頁能解的兩種壓縮形式，`src/window.js` 把測出來的值對映到你螢幕上的灰階。
- **那些指認身份的欄位是列給你看的，不給別人。** 這一頁會把你檔案裡每一個點名或者縮小範圍的欄位都列印出來。要把一張切片發給別人的人正需要這個答案，可是沒有哪個閱片器給。它只出現在你眼前的螢幕上，不去別的任何地方。本儲存庫裡沒有任何一個分析事件會帶走其中一星半點，就算有，這一頁也送不出去。
- **它只讀，不寫。** 這裡沒有一個按鈕會改動你的檔案，也沒有能改動它的程式碼。你能帶走的是螢幕上那一幀的 PNG，和頭資訊的一份文字，兩樣都是在這一頁裡用已經在頁面上的東西拼出來的。原件原封不動地留在你的硬碟上，關掉分頁會怎樣，老實的答案也是這個。
- **谷歌載入了什麼，又拿不到什麼。** 廣告和統計指令碼來自谷歌。這兩個都拿不到關於你檔案的任何東西，畫素拿不到，縮圖拿不到，姓名、標籤、病人、檔名都拿不到。解析、解碼、繪製影像的每一行都由本站自己提供，也都寫在儲存庫裡。
- **捐贈按鈕載入了什麼，又拿不到什麼。** 頁面頂部那個「Buy me a coffee」按鈕由 cdnjs.buymeacoffee.com 的指令碼畫出來，字型取自 Google Fonts。它就是個連結而已，不會報告訪問，也拿不到關於你或者你檔案的任何東西。你不點它就什麼都不會發生，點下去到的是別人的網站。
- **斷網也能用。** 把網路斷掉，這一頁的每一處照樣運轉。這是最簡單的證明。要是有個工具把你的影像送出去讓別人畫，拔掉網線的那一刻它就停了。

**你可以自己核對。**上面這些不用你信。這個頁面是儲存庫裡的模板和配置產生出來的，構建指令碼你能讀，也能自己跑一遍，跑出來的結果就提交在 `dist` 分支上。拿實際發給你的內容，跟你自己從原始碼構建出來的結果對一遍就知道了： https://github.com/A-Box-of-Tools/website

最值得先讀的幾個檔案：`config/site.toml` 裡是 Content-Security-Policy，走遍檔案的解析器在 `src/dicom.js`，畫素解碼在 `src/pixels.js`，醫院匯出時用得最多的那個編解碼器在 `src/jpeg-lossless.js`，窗寬窗位在 `src/window.js`。這幾個檔案裡沒有一行能碰到網路。
