Poszedłem dalej i powtórzyłem eksperyment, aby sprawdzić, czy mogę się dowiedzieć, co się dzieje.
Procedura
Wygenerowałem losowy obraz RGB 256 na 256 pikseli przy użyciu filtra „Solid Noise” w GIMP (Filtry> Renderowanie> Chmury> Solid Noise ...) przy użyciu ustawień domyślnych (pokazanych poniżej):
A wynik:
Następnie zapisałem obraz jako JPEG przy użyciu ustawień domyślnych:
Następnie przeniosłem obraz do systemu Windows i otworzyłem go za pomocą Przeglądarki fotografii systemu Windows, klikając obraz prawym przyciskiem myszy w Eksploratorze plików i wybierając z menu opcję Podgląd . Następnie obróciłem obraz za pomocą przycisków na dole i zapisałem obraz, przechodząc do następnego obrazu za pomocą klawiszy strzałek.
Dla każdego z poniższych testów zacząłem od kopii oryginalnego obrazu i obróciłem (kliknąłem przycisk obrotu) odpowiednią liczbę razy przed zapisaniem. Oto rozmiary resltingu ( 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
Natychmiastowe obserwacje
- Windows Photo Viewer (WPV) znacznie zwiększa rozmiar; w tym teście kwota wzrostu jest około cztery razy!
- Wszystkie nowe obrazy powiększają się do mniej więcej tego samego rozmiaru, ale nie są identyczne.
- WPV nie koduje ani nawet nie zapisuje obrazu, gdy zostanie on obrócony o wielokrotność 360 stopni. (Znacznik czasu 11:27 oznacza datę pierwszego skopiowania plików).
Używanie cmp -l
plików, które powinny mieć identyczną treść, pozwala nam zobaczyć, gdzie różnią się pliki.
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
Pliki te różnią się tylko czterema bajtami (w rzeczywistości znacznikiem czasu), co oznacza, że WPV robi to samo za każdym razem; teraz musimy tylko dowiedzieć się, co to jest.
Szczegółowe obserwacje
W tym celu użyłem JPEGsnoop, aby zobaczyć, co dokładnie jest na obrazach.
Ponieważ wyniki są dość długie, powiązałem je z nimi jako sedno . Oto podsumowanie różnic:
GIMP używa tylko segmentu APP0
(JFIF) i COM
(komentarza) dla metadanych. WPV pozostawia APP0
segment nietknięty, ale z ciekawością dodaje bajt zerowy do komentarza (tak, że jest zakończony zerem ).
WPV dodaje dwa APP1
segmenty, które są metadanymi Exif i XMP. Segmenty te mają odpowiednio 4286 i 12726 bajtów. Razem stanowią prawie cały wzrost wielkości plików.
GIMP tworzy progresywny JPEG, podczas gdy WPV tworzy wyjściowy (nie progresywny) JPEG. Z tego powodu obraz GIMP ma wiele segmentów skanowania, podczas gdy obraz WPV ma tylko jeden. Z mojego doświadczenia wynika, że obraz progresywny jest czasem nieco mniejszy.
GIMP zastosował podpróbkowanie 1 × 1, a WPV zastosował podpróbkowanie 2 × 2. To prowadzi mnie do przekonania, że WPV nie używa „prawdziwej” bezstratnej rotacji, chyba że w jakiś sposób jest w stanie wykryć, że jest to obraz czarno-biały.
Aby rozwiązać te problemy, przeprowadziłem drugi test.
Procedura
Wykonałem podobne kroki do pierwszego testu. Utworzyłem losowy obraz RGB 256 × 256 przy użyciu filtra szumów RGB (Filtry> Nos> Nos RGB ...) z następującymi ustawieniami:
Oto wynik:
Wyeksportowałem plik jako JPEG przy użyciu następujących ustawień:
Progresywne zostało wyłączone, ale podpróbkowanie jest nadal ustawione na 4: 4: 4 (co jest inną nazwą dla podpróbkowania 1 × 1). Jakość zostaje zwiększona do 98.
Skopiowałem obraz i obróciłem kopię w prawo; następnie skopiowałem obróconą wersję i obróciłem tę kopię przeciwnie do ruchu wskazówek zegara, abyśmy mogli bezpośrednio porównać jakość oryginału i przetworzonej kopii WPV.
Wyniki
-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
Chociaż wzrost ten czas jest mniejszy w kategoriach względnych (około 40%), wzrost absolutny jest jeszcze większy - około 62 kB. Sugeruje to, że WMV używa mniej wydajnego kodowania.
Użyję ImageMagick porównać dwa obrazy:
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
Są zerowe pikseli różne między pierwotnym i obróconej kopii. Tak więc, nawet jeśli WPV nie używa „prawdziwej” bezstratnej rotacji, robi wystarczająco dobrą robotę. Podejrzewam, że wiem, co się dzieje, i aby wyjaśnić, przejdę trochę do matematyki związanej z kompresją JPEG.
Algorytm kompresji JPEG dzieli obraz na bloki 8 x 8 pikseli. Każdy z tych bloków jest następnie poddawany dyskretnej transformacji kosinusowej (DCT) . Otrzymane współczynniki DCT opisują blok jako sumę fal o różnych częstotliwościach. Algorytm następnie „wyrzuca” w falach o wysokiej częstotliwości pewne informacje, które odpowiadają szumowi i bardzo małym szczegółom. Proces dekodowania odwraca DCT, dodając zgromadzone fale razem, aby odzyskać blok.
Możliwe jest obracanie „fal” DCT bez faktycznego cofania i ponawiania transformacji (w zasadzie zamieniasz wszystkie fale poziome na fale pionowe i odwrotnie). Wydaje mi się, że w WPV obraz jest dekodowany, obracany, a następnie ponownie kodowany. Podczas procesu ponownego kodowania, ponieważ rozmiar naszego obrazu jest wielokrotnością 8 w obu wymiarach, każdy z nowych bloków odpowiada jednemu z oryginalnych bloków. Co ważne, ponieważ każdy blok nie ma składników o wysokiej częstotliwości, algorytm nie wyrzuca żadnych informacji i znajduje dokładnie odpowiednie składniki DCT, które miałby „prawdziwy” bezstratny obrót.
Na koniec jeszcze raz przyjrzę się składnikom plików JPEG. Wyniki są ponownie łączone jako istoty . Porównując dwa:
Obraz WPV zawiera dodatkowe 4286 + 2 bajty metadanych Exif, 1 dodatkowy bajt w komentarzu i 12 726 + 2 bajty metadanych XMP. Jest to łącznie 17.017 bajtów dodatkowych metadanych. Do czego służą wszystkie te dane? Zerknąłem do pliku z moim zaufanym edytorem szesnastkowym i kopią odpowiednich standardów:
Metadane Exif mają strukturę podobną do obrazu TIFF, który zawiera wiele tagów (jest o wiele bardziej złożona, ale przeskoczę nad tym). Większość bajtów w segmencie Exif znajduje się w dwóch identycznych znacznikach o numerze EA1C
(59 932 dziesiętnym). Tego numeru znacznika nie udokumentowano nigdzie, gdzie mogłem znaleźć. Oba tagi zawierają 2060 bajtów typu „niezdefiniowany”, które są bajtami zerowymi, z wyjątkiem pierwszych sześciu ( 1C EA 00 00 00 08
). Nie mam pojęcia, co to za tagi, dlaczego są dwa i dlaczego muszą mieć 2 kB każdy.
Metadane XMP to tak naprawdę cały osadzony dokument XML z przestrzenią nazw i długimi identyfikatorami UUID, który zawiera tylko ciąg wersji WPV (który był już w metadanych Exif). Jednak to tylko około 400 bajtów. Pozostała część segmentu to 122 powtórzenia 100 spacji, po których następuje nowa linia . To ponad 12 000 bajtów całkowicie zmarnowanej przestrzeni.
Podobnie jak w poprzednim teście, zarówno GIMP, jak i WPV używają tych samych tabel kwantyzacji DCT. Oznacza to, że powinni obliczać dokładnie te same współczynniki DCT, dlatego obrazy są dokładnie takie same. Nie jestem pewien, czy WPV po prostu używa tych samych tabel kwantyzacji, czy kopiuje je z danych wejściowych.
W przeciwieństwie do poprzedniego testu, tym razem WPV korzysta z podpróbkowania 1 × 1, więc może faktycznie wykryć, że jest to kolorowy obraz (lub przynajmniej, że wyższe próbki są konieczne do bezstratnego ponownego kodowania obrazu).
GIMP i WPV używają różnych tabel Huffmana (część etapu kodowania entropijnego). Tabele WPV są większe o łącznie 279 bajtów, aw jednym przypadku zawierają 7 razy więcej kodów.
Patrząc na statystyki JPEGsnoop, widzimy, że niektóre z tych kodów są rzadko używane. Na przykład w ID: 1, Class: AC
tabeli spośród 119 zdefiniowanych 16-bitowych kodów faktycznie używanych jest tylko 23. Ogólnie rzecz biorąc, rzeczywisty segment skanowania jest o 28,5% większy w wersji WPV.
Podsumowanie
WPV może nie wykonywać „prawdziwych” obrotów bezstratnych, ale wydają się być praktycznie bezstratne.
Dodatkowy rozmiar wynika częściowo ze stałej ilości dodanych metadanych, a częściowo z mniej wydajnego kodowania entropii.
Informacje o wersji:
System operacyjny (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
System operacyjny (Windows):
GIMP (Linux): 2.8.14 (z pakietu gimp
, wersja 2.8.14-1+deb8u1
)
Przeglądarka zdjęć w oknie (zgodnie z metadanymi obrazu):
Microsoft Windows Photo Viewer 10.0.10586.0