# 同一張照片重存後，還讀得到位置嗎？metadata-extractor 真實照片實測

- 網址：https://blog.valenvan.uk/posts/drewnoakes-metadata-extractor.html
- 發布日期：2026-11-07
- 測試設備：Mac mini M4 Pro（12 核、64GB）
- 專案：drewnoakes/metadata-extractor（https://github.com/drewnoakes/metadata-extractor），Apache-2.0 授權
- 測試版本：metadata-extractor 2.19.0 / xmpcore 6.1.11 / OpenJDK 17.0.21
- 實測影片：https://www.youtube.com/shorts/73IoT4qfX04

## 重點摘要

- 用獨立來源的真實照片，下載原檔讀出相機型號、拍攝時間與GPS三項資料。
- 同一照片經Java ImageIO重存後，這三項均讀不到；兩檔解析錯誤均為0。
- 原檔與重存檔均為3765×5647；相同尺寸不代表附帶資料相同。
- metadata-extractor負責讀取；本次重存由Java ImageIO執行。
- **結論：** 傳原檔前可先讀取附帶資料；不能只看畫面判斷。
- **適合：** 會寫Java、想批次檢查照片資料的人
- **不適合：** 需要現成圖形介面或一鍵清除位置的人

| 實測項目 | 結果 |
|---|---|
| 輸入 | 台北101真實照片下載原檔及其ImageIO重存檔 |
| 原檔 | 三項皆讀到 |
| 重存 | 三項皆讀不到 |
| 解析錯誤 | 兩檔均0 |

旅行回來要把照片原檔傳給朋友，除了看畫面，你可能還想知道檔案附帶什麼資料。這一集實測 metadata-extractor，用的是獨立於專案的真實台北101照片，不再用它附帶的測試檔。測試不需要把私人照片或原始座標放進影片；影片呈現必要結果，完整輸入與輸出留作本機證據。這張公開照片也不是我們親自拍的。

## 測什麼、為什麼這樣測

這次直接讀取 Balon Greyjoy 拍攝、以 CC0 公開的照片下載原檔。接著以 Java ImageIO 重新輸出同一張照片，再交給同一個讀取工具檢查。問題是：畫面看起來相同，附帶的相機、時間、座標是否仍相同？這個對照符合傳檔前檢查的用途，不是把人造座標寫進照片，或拿預設答案做一次展示。

設備為 Mac mini M4 Pro（12核、64GB），執行環境是 Debian 12、OpenJDK 17.0.21；受測程式庫版本固定為 2.19.0，依賴 xmpcore 6.1.11。沒有呼叫付費 API。

## 準備與下載

需要 Java 17 JDK，`java -version` 與 `javac -version` 都要成功。它是 Java 程式庫，沒有點兩下就能操作的視窗。請在獨立資料夾下載兩個 jar，再放入想檢查的照片。本文使用的公開原檔可照下面取得；讀自己的照片時，只需換成本機檔名，不必上傳。

```bash
mkdir photo-check
cd photo-check
curl -fLO https://repo1.maven.org/maven2/com/drewnoakes/metadata-extractor/2.19.0/metadata-extractor-2.19.0.jar
curl -fLO https://repo1.maven.org/maven2/com/adobe/xmp/xmpcore/6.1.11/xmpcore-6.1.11.jar
curl -fL -o original.jpg https://upload.wikimedia.org/wikipedia/commons/4/4b/20190416_Taipei_101-1.jpg
CP=metadata-extractor-2.19.0.jar:xmpcore-6.1.11.jar
```

## 先查原檔，再重存檢查

把下列內容存成 `Inspect.java`。讀取每張檔案後，它分別列出相機型號、原始拍攝時間、座標與解析錯誤數。讀不到欄位和程式執行失敗是兩回事；若讀檔例外，程式會停止，不能把失敗當作沒有座標。

```java
import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.*;
import com.drew.metadata.exif.*;
import com.drew.lang.GeoLocation;
import java.io.File;
public class Inspect {
 public static void main(String[] args) throws Exception {
  for (String path : args) {
   Metadata m=ImageMetadataReader.readMetadata(new File(path));
   ExifIFD0Directory e=m.getFirstDirectoryOfType(ExifIFD0Directory.class);
   ExifSubIFDDirectory d=m.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
   GpsDirectory g=m.getFirstDirectoryOfType(GpsDirectory.class);
   GeoLocation l=g==null?null:g.getGeoLocation();
   System.out.println(new File(path).getName());
   System.out.println("Model: "+(e==null?"not found":e.getString(ExifIFD0Directory.TAG_MODEL)));
   System.out.println("Date: "+(d==null?"not found":d.getString(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL)));
   System.out.println("GPS: "+(l==null?"not found":l.getLatitude()+", "+l.getLongitude()));
   int errors=0; for(Directory dir:m.getDirectories()) for(String err:dir.getErrors()){errors++;System.err.println(err);}
   System.out.println("Errors: "+errors);
  }
 }
}
```

再將以下存成 `Reencode.java`。這是用來重新輸出 JPEG 的另一段程式，**不是 metadata-extractor 的清除功能**。JPEG 重存是有損壓縮；雖然尺寸不變，像素不保證完全相等。這次是檢查欄位差異，不是推薦把重存當成通用隱私保證。

```java
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
public class Reencode {
 public static void main(String[] a) throws Exception {
  BufferedImage img=ImageIO.read(new File(a[0]));
  if(img==null || !ImageIO.write(img,"jpg",new File(a[1]))) throw new Exception("JPEG conversion failed");
  BufferedImage b=ImageIO.read(new File(a[1]));
  System.out.println("Reencoded pixels: "+img.getWidth()+"x"+img.getHeight()+" -> "+b.getWidth()+"x"+b.getHeight());
 }
}
```

```bash
javac -cp "$CP" Inspect.java Reencode.java
java Reencode original.jpg reencoded.jpg
java -cp "$CP:." Inspect original.jpg reencoded.jpg
```

## 實際結果

|檢查欄位|下載原檔|ImageIO 重存檔|
|---|---|---|
|相機型號|Canon EOS 5D Mark III|讀不到|
|拍攝時間|2019:04:16 14:33:44|讀不到|
|GPS|讀得到|讀不到|
|解析錯誤|0|0|
|影像尺寸|3765×5647|3765×5647|

![實際執行讀取原檔與重存檔，結果不同](https://blog.valenvan.uk/img/drewnoakes-metadata-extractor-article_1.png)

這裡的三項，專指表格前三項，不是說原檔只有三個資料欄位。工具從原檔讀出的座標與 Commons 頁面的公開拍攝位置相符，但欄位本身可以修改，不能據此證明一個人當時真的在哪裡。重存檔這三項都讀不到，表示這次重新輸出沒有保留它們，不表示所有轉檔軟體都如此。

## 適合誰、遇到問題怎麼辦

我的看法：會寫程式、要批次檢查照片附帶資料的人，用它能把檢查整合進工作流程。完全不寫程式的人，這個程式庫仍有上手門檻。出現 `javac: command not found`，要確認裝的是 JDK；出現缺少 `com/adobe/xmp`，要確認兩個 jar 都列在 classpath。上述指令適用 Linux／macOS，Windows 的 classpath 分隔符號須改為分號。

這次沒有測通訊軟體上傳、手機截圖或 HEIC，不推論它們是否保留位置；也沒有測復原被移除的資料。結論是：不能只看照片畫面，就判斷原檔帶了什麼；先用工具讀一次，才能知道這份檔案實際可讀到哪些欄位。

專案：[metadata-extractor](https://github.com/drewnoakes/metadata-extractor)，Apache-2.0。
照片：[20190416 Taipei 101-1.jpg](https://commons.wikimedia.org/wiki/File:20190416_Taipei_101-1.jpg)，Balon Greyjoy，[CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/)。影片只展示測試結果，原圖不入鏡；資料來源留存於本機證據。
