Tôi đã tiếp tục và lặp lại thí nghiệm để xem liệu tôi có thể biết chuyện gì đang xảy ra không.
Thủ tục
Tôi đã tạo một hình ảnh RGB 256 x 256 pixel ngẫu nhiên bằng bộ lọc "Solid noise" trong GIMP (Bộ lọc> Kết xuất> Đám mây> Nhiễu rắn ...) bằng cách sử dụng cài đặt mặc định (hiển thị bên dưới):
Và kết quả:
Sau đó, tôi đã lưu hình ảnh dưới dạng JPEG bằng cách sử dụng các cài đặt mặc định:
Sau đó, tôi chuyển hình ảnh sang Windows và mở hình ảnh bằng Windows Photo Viewer bằng cách nhấp chuột phải vào hình ảnh trong File Explorer và chọn Xem trước từ menu. Sau đó, tôi xoay hình ảnh bằng cách sử dụng các nút ở phía dưới và lưu hình ảnh bằng cách điều hướng đến hình ảnh tiếp theo bằng các phím mũi tên.
Đối với mỗi thử nghiệm bên dưới, tôi bắt đầu với một bản sao của hình ảnh gốc và được xoay (nhấp vào nút xoay) số lần tương ứng trước khi lưu. Dưới đây là các kích thước thay đổi ( ls -l -r
):
size in bytes last-modified date
VVVVV VVVVV
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:24 original.jpg
-rwxrwx--- 1 root vboxsf 23645 Nov 8 11:30 cw.jpg
-rwxrwx--- 1 root vboxsf 23636 Nov 8 11:30 cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:30 cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:27 cw-cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:31 cw-cw-cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:29 ccw.jpg
-rwxrwx--- 1 root vboxsf 23636 Nov 8 11:29 ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 23645 Nov 8 11:29 ccw-ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:27 ccw-ccw-ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:30 ccw-ccw-ccw-ccw-ccw.jpg
Quan sát ngay lập tức
- Windows Photo Viewer (WPV) tăng kích thước đáng kể; số lượng tăng khoảng bốn lần trong thử nghiệm này!
- Tất cả các hình ảnh mới tăng lên cùng kích thước, nhưng chúng không giống nhau.
- WPV không mã hóa lại hoặc thậm chí lưu lại hình ảnh khi nó được xoay bởi bội số 360 độ. (Dấu thời gian, 11:27, là khi các tệp được sao chép lần đầu tiên.)
Sử dụng cmp -l
trên các tệp nên có nội dung giống hệt nhau cho phép chúng tôi xem các tệp khác nhau ở đâu.
robert@unity ../jpeg-rotate-test % cmp -l cw.jpg ccw-ccw-ccw.jpg
2223 63 62
2224 60 71
2226 60 64
2227 60 66
robert@unity ../jpeg-rotate-test % cmp -l cw-cw.jpg ccw-ccw.jpg
2223 63 62
2224 60 71
2226 60 64
2227 62 64
robert@unity ..jpeg-rotate-test % cmp -l ccw.jpg cw-cw-cw.jpg
2223 62 63
2224 71 60
2226 64 60
2227 61 64
robert@unity ../jpeg-rotate-test % cmp -l cw.jpg cw-cw-cw-cw-cw.jpg
2221 60 61
2223 63 61
2224 60 66
2226 60 61
2227 60 61
robert@unity ../jpeg-rotate-test % cmp -l ccw.jpg ccw-ccw-ccw-ccw-ccw.jpg
2223 62 63
2224 71 60
2226 64 65
2227 61 64
Các tệp này chỉ khác nhau ở bốn byte (thực tế là trong dấu thời gian), có nghĩa là WPV luôn làm điều tương tự; bây giờ chúng ta chỉ cần tìm ra đó là gì.
Quan sát chi tiết
Đối với điều này, tôi đã sử dụng JPEGsnoop để xem chính xác những gì trong hình ảnh.
Vì các đầu ra khá dài nên tôi đã liên kết với chúng như một ý chính . Dưới đây là tóm tắt về sự khác biệt:
GIMP chỉ sử dụng phân đoạn APP0
(JFIF) và COM
(bình luận) cho siêu dữ liệu. WPV để APP0
phân đoạn không bị ảnh hưởng, nhưng tò mò thêm một byte null vào bình luận (để nó bị chấm dứt null).
WPV thêm hai APP1
phân đoạn, đó là siêu dữ liệu Exif và XMP. Các phân đoạn này lần lượt là 4286 và 12726 byte. Họ cùng nhau chiếm gần như toàn bộ sự gia tăng của tập tin.
GIMP tạo ra một JPEG lũy tiến, trong khi WPV tạo ra một JPEG cơ bản (không tiến bộ). Vì lý do này, hình ảnh của GIMP có nhiều phân đoạn quét, trong khi hình ảnh WPV chỉ có một. Theo kinh nghiệm của tôi, hình ảnh tiến bộ đôi khi hơi nhỏ hơn.
GIMP đã sử dụng mẫu phụ sắc độ 1 × 1, trong khi WPV sử dụng mẫu phụ 2 × 2. Điều này khiến tôi tin rằng WPV không sử dụng phép quay "lossless" thực sự, trừ khi bằng cách nào đó có thể phát hiện ra đây là hình ảnh đen trắng.
Để giải quyết những vấn đề này, tôi đã chạy thử nghiệm thứ hai.
Thủ tục
Tôi đã làm theo các bước tương tự để thử nghiệm đầu tiên. Tôi đã tạo một hình ảnh RGB 256 × 256 ngẫu nhiên bằng bộ lọc nhiễu RGB (Bộ lọc> Mũi> Mũi RGB ...) với các cài đặt sau:
Đây là kết quả:
Tôi đã xuất tệp dưới dạng JPEG bằng các cài đặt sau:
Tiến trình đã bị tắt, nhưng Lấy mẫu con vẫn được đặt thành 4: 4: 4 (tên gọi khác của mẫu phụ 1 × 1). Chất lượng được tăng lên 98.
Tôi đã sao chép hình ảnh và xoay bản sao theo chiều kim đồng hồ; sau đó sao chép phiên bản xoay và xoay bản sao đó ngược chiều kim đồng hồ, để chúng ta có thể so sánh trực tiếp chất lượng giữa bản gốc và bản sao được xử lý WPV.
Các kết quả
-rwxrwx--- 1 root vboxsf 159774 Nov 8 16:21 original-random.jpg
-rwxrwx--- 1 root vboxsf 222404 Nov 8 16:24 cw-random.jpg
-rwxrwx--- 1 root vboxsf 222467 Nov 8 16:24 cw-ccw-random.jpg
Mặc dù mức tăng lần này nhỏ hơn về mặt tương đối (khoảng 40%), mức tăng tuyệt đối thậm chí còn lớn hơn khoảng 62 kB. Điều này cho thấy WMV đang sử dụng mã hóa kém hiệu quả hơn.
Tôi sẽ sử dụng ImageMagick để so sánh hai hình ảnh:
robert@unity ../jpeg-rotate-test % compare -verbose -metric AE original-random.jpg cw-ccw-random.jpg null:
original-random.jpg JPEG 256x256 256x256+0+0 8-bit sRGB 160KB 0.000u 0:00.009
cw-ccw-random.jpg JPEG 256x256 256x256+0+0 8-bit sRGB 222KB 0.010u 0:00.010
Image: original-random.jpg
Channel distortion: AE
red: 0
green: 0
blue: 0
all: 0
original-random.jpg=> JPEG 256x256 256x256+0+0 8-bit sRGB 0.050u 0:00.020
Không có pixel nào khác nhau giữa bản gốc và bản sao xoay. Vì vậy, ngay cả khi WPV không sử dụng vòng quay "lossless" thực sự, nó vẫn đang làm một công việc đủ tốt. Tôi nghi ngờ tôi biết những gì đang xảy ra, và để giải thích tôi sẽ chuyển hướng một chút vào toán học đằng sau việc nén JPEG.
Thuật toán nén JPEG chia hình ảnh thành các khối 8 × 8 pixel. Mỗi một trong số các khối này sau đó phải chịu Biến đổi Cosine rời rạc (DCT) . Các hệ số DCT kết quả mô tả khối là tổng của các sóng tần số khác nhau. Thuật toán sau đó "vứt bỏ" một số thông tin trong sóng tần số cao tương ứng với nhiễu và chi tiết rất nhỏ. Quá trình giải mã đảo ngược DCT, cộng các sóng được lưu trữ lại với nhau để lấy lại khối.
Có thể xoay "sóng" DCT mà không thực sự hoàn tác và làm lại biến đổi (về cơ bản, bạn biến tất cả các sóng ngang thành sóng dọc và ngược lại). Những gì tôi nghĩ xảy ra trong WPV là hình ảnh thực sự được giải mã, xoay và sau đó được mã hóa lại. Trong quá trình mã hóa lại, vì kích thước hình ảnh của chúng tôi là bội số của cả hai chiều, mỗi khối mới tương ứng với một trong các khối ban đầu. Điều quan trọng là, vì mỗi khối không có các thành phần tần số cao, thuật toán sẽ không loại bỏ bất kỳ thông tin nào và tìm thấy chính xác các thành phần DCT đúng mà một phép quay không mất "thực" sẽ có.
Cuối cùng, tôi sẽ xem lại các thành phần của các tệp JPEG. Các kết quả được liên kết lại như là ý chính . So sánh hai:
Hình ảnh WPV chứa thêm siêu dữ liệu Exif có thêm 4286 + 2 byte, thêm 1 byte trong nhận xét và 12.726 + 2 byte siêu dữ liệu XMP. Đây là tổng số 17.017 byte siêu dữ liệu bổ sung. Tất cả những gì dữ liệu được sử dụng cho? Tôi nhìn vào tập tin với trình soạn thảo hex đáng tin cậy của tôi và một bản sao của các tiêu chuẩn có liên quan:
Exif siêu dữ liệu có cấu trúc giống như một hình ảnh TIFF, trong đó có một số thẻ (có cách phức tạp hơn, nhưng tôi sẽ bỏ qua ngay nó). Hầu hết các byte trong phân đoạn Exif được chứa trong hai thẻ giống hệt nhau với số thẻ EA1C
(59.932 thập phân). Số thẻ đó không được ghi lại ở bất cứ đâu tôi có thể tìm thấy. Cả hai thẻ chứa 2060 byte của kiểu "không xác định", mà tất cả đều rỗng byte trừ trong sáu đầu tiên ( 1C EA 00 00 00 08
). Tôi không biết những thẻ này là gì, tại sao có hai trong số chúng, và tại sao chúng cần có 2 kB mỗi thẻ.
Siêu dữ liệu XMP thực sự là toàn bộ tài liệu XML được nhúng với không gian tên và UUID dài, chỉ chứa chuỗi phiên bản WPV (đã có trong siêu dữ liệu Exif). Tuy nhiên, điều đó chỉ chiếm khoảng 400 byte. Phần còn lại của phân khúc là 122 lần lặp lại của 100 khoảng trắng theo sau là một dòng mới . Đó là hơn 12.000 byte không gian lãng phí hoàn toàn.
Giống như thử nghiệm trước đó, cả GIMP và WPV đều sử dụng các bảng lượng tử hóa DCT giống nhau. Điều này có nghĩa là họ nên tính toán chính xác các hệ số DCT, đó là lý do tại sao các hình ảnh giống hệt nhau. Tôi không chắc chắn nếu WPV chỉ sử dụng các bảng lượng tử hóa tương tự hoặc nếu nó sao chép các bảng từ đầu vào.
Không giống như thử nghiệm trước, lần này WPV sử dụng mẫu phụ 1 × 1, do đó, thực tế có thể phát hiện ra rằng đây là hình ảnh màu (hoặc ít nhất là các mẫu cao hơn là cần thiết để mã hóa lại hình ảnh một cách dễ dàng).
GIMP và WPV sử dụng các bảng Huffman khác nhau (một phần của bước mã hóa entropy). Các bảng cho WPV lớn hơn tổng cộng 279 byte và trong một trường hợp chứa gấp 7 lần số mã.
Nhìn vào số liệu thống kê của JPEGsnoop, chúng ta có thể thấy rằng một số mã này hiếm khi được sử dụng. Ví dụ, trong ID: 1, Class: AC
bảng, trong số 119 mã 16 bit được xác định, chỉ có 23 mã thực sự được sử dụng. Nhìn chung, phân khúc quét thực tế lớn hơn 28,5% trong phiên bản WPV.
Tóm lược
WPV có thể không thực hiện các phép quay "lossless" thực sự, nhưng các phép quay dường như không thực sự mất.
Kích thước bổ sung một phần là do một lượng siêu dữ liệu được thêm vào cố định và một phần do mã hóa entropy kém hiệu quả hơn.
Thông tin phiên bản:
Hệ điều hành (Linux) ( uname -a
):
Linux unity 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u1 (2016-09-03) x86_64 GNU/Linux
HĐH (Windows):
GIMP (Linux): 2.8,14 (từ gói gimp
, phiên bản 2.8.14-1+deb8u1
)
Window Photo Viewer (theo siêu dữ liệu hình ảnh):
Microsoft Windows Photo Viewer 10.0.10586.0