Định dạng TIFF
Tagged Image File Format
Cấu trúc phần đầu file
TIFF là ông tổ của siêu dữ liệu ảnh. Khi bạn thấy dữ liệu EXIF trong một file JPEG, thực chất đó là một cấu trúc TIFF nằm gọn bên trong. Hiểu TIFF nghĩa là hiểu cách phần lớn siêu dữ liệu ảnh vận hành.
File bắt đầu bằng một header 8 byte cho bạn biết hai điều quan trọng: thứ tự byte (Intel hay Motorola) và chỗ tìm IFD đầu tiên. Từ đó trở đi, tất cả là chuyện lần theo con trỏ.
Cấu trúc file TIFF
Header TIFF
| Offset | Hex | ASCII | |||||||
|---|---|---|---|---|---|---|---|---|---|
| 0000 | 49492A0008000000 | II*..... | |||||||
Thứ tự byte
49 49 (II)Intel:little-endian (byte ít quan trọng nhất đứng trước)
4D 4D (MM)Motorola:big-endian (byte quan trọng nhất đứng trước)
Cấu trúc IFD
IFD là viết tắt của Image File Directory, nhưng bạn cứ hình dung nó như một mục lục. Đó là một danh sách phẳng các thẻ, mỗi thẻ trỏ tới một mẩu dữ liệu. Điểm khéo là IFD có thể trỏ tới IFD khác, tạo thành một cấu trúc cây.
Bố cục của một IFD
Cấu trúc một mục thẻ (12 byte)
Nếu dữ liệu vừa trong 4 byte thì nó được lưu thẳng vào trường giá trị. Nếu không, trường đó chứa offset trỏ tới nơi cất dữ liệu.
Các kiểu thẻ
TIFF định kiểu rất chặt. Mỗi thẻ không chỉ nói nó chứa gì, mà còn nói phải hiểu các byte đó ra sao. Vì vậy bạn phải nắm hệ thống kiểu thì mới đọc TIFF cho đúng.
| ID | Tên | Kích thước | Mô tả |
|---|---|---|---|
| 1 | BYTE | 1 | Số nguyên 8 bit không dấu |
| 2 | ASCII | 1 | Chuỗi kết thúc bằng null (8 bit) |
| 3 | SHORT | 2 | Số nguyên 16 bit không dấu |
| 4 | LONG | 4 | Số nguyên 32 bit không dấu |
| 5 | RATIONAL | 8 | Hai số LONG: tử số/mẫu số |
| 6 | SBYTE | 1 | Số nguyên 8 bit có dấu |
| 7 | UNDEFINED | 1 | Byte thô (dữ liệu nhị phân) |
| 8 | SSHORT | 2 | Số nguyên 16 bit có dấu |
| 9 | SLONG | 4 | Số nguyên 32 bit có dấu |
| 10 | SRATIONAL | 8 | Hai số SLONG: tử/mẫu có dấu |
| 11 | FLOAT | 4 | Số thực IEEE 32 bit |
| 12 | DOUBLE | 8 | Số thực IEEE 64 bit |
| 13 | IFD | 4 | Con trỏ tới IFD lồng bên trong |
Quy tắc lưu giá trị
Nếu kích thước × số lượng ≤ 4 byte thì giá trị được lưu thẳng vào trường 4 byte. Nếu không, trường đó chứa offset trỏ tới nơi dữ liệu được cất trong file.
Cách tính offset của IFD
Phần khó nhất khi đọc TIFF là lần theo chuỗi offset. Mọi thứ đều tính từ đầu file, và bạn sẽ phải nhảy qua nhảy lại khá nhiều. Phép tính như sau:
IFD0_offset = bytes[4:8] // Lấy từ header TIFF
next_IFD = IFD0_offset + 2 + (entry_count × 12) + 4
subIFD_offset = tag_value // Lấy từ thẻ con trỏ (0x8769, 0x8825)
Những thẻ quan trọng
Thẻ dữ liệu ảnh (được giữ lại)
0x0100:ImageWidth0x0101:ImageLength0x0102:BitsPerSample0x0103:Compression0x0111:StripOffsets0x0117:StripByteCountsThẻ siêu dữ liệu (bị xóa)
0x010F:Make (hãng sản xuất máy ảnh)0x0110:Model (model máy ảnh)0x0132:DateTime0x013B:Artist0x8298:Copyright0x9003:DateTimeOriginalThẻ con trỏ (tới các sub-IFD)
0x8769:ExifIFDPointer0x8825:GPSInfoIFDPointer0xA005:InteroperabilityIFDPointerCác SubIFD
IFD chính (IFD0) thường chứa các "thẻ con trỏ" tham chiếu tới những thư mục con. Nhờ vậy EXIF, GPS và các siêu dữ liệu khác được gom thành từng nhóm hợp lý, còn IFD chính vẫn gọn gàng.
SubIFD chứa EXIF
Chứa siêu dữ liệu riêng của máy ảnh: phơi sáng, khẩu độ, ISO, tiêu cự, đèn flash, cân bằng trắng và nhiều thứ nữa.
SubIFD chứa GPS
Chứa dữ liệu vị trí: vĩ độ, kinh độ, độ cao, thời điểm, số vệ tinh, tốc độ, hướng di chuyển. Rủi ro riêng tư lớn nhất.
Maker Notes
Dữ liệu riêng của từng hãng máy ảnh. Định dạng khác nhau tùy hãng. Có thể chứa số sê-ri, phiên bản firmware, các thiết lập tùy biến.
PicScrub xử lý TIFF như thế nào
Đọc header
Xác định thứ tự byte (II/MM) và tìm IFD đầu tiên
Lập danh sách thẻ được phép
Xác định những thẻ thiết yếu để hiển thị ảnh
Lọc các mục trong IFD
Xóa các thẻ siêu dữ liệu, đặt con trỏ SubIFD về 0
Ghi lại file
Dựng lại file TIFF với các IFD đã sạch và dữ liệu ảnh chép nguyên xi
Tính lại các offset
File TIFF dùng offset ở khắp nơi. Khi siêu dữ liệu bị xóa, PicScrub phải tính lại toàn bộ offset để file vẫn còn nguyên vẹn.