Warum ändert sich die Dateigröße, wenn ein Bild verlustfrei gedreht wird?

Ich habe nach Methoden zur verlustfreien Bilddrehung gesucht und bin auf diese Frage gestoßen, die es ziemlich gut erklärt:

Sind "Windows Photo Viewer"-Rotationen verlustfrei?

Also habe ich ein 256×256-JPEG mit zufälligen Pixeln (Photoshop-Wolkenfilter) erstellt und es dann mit Windows Picture Viewer gedreht. Nach der Drehung hat sich die Dateigröße tatsächlich erhöht, aber nur bei der ersten Drehung. Bei jeder weiteren Drehung danach blieb die Dateigröße unverändert. Ich weiß, dass es verlustfrei dreht, weil ich es mehrmals ohne merklichen Qualitätsverlust gedreht habe, während ein 257 × 257-Bild, das 20 Mal gedreht wurde, sehr verlustbehaftet wurde.

Um wie viel hat sich die Dateigröße in Ihren Tests erhöht?
@JamesSnell Ich wusste, dass ich das hätte aufnehmen sollen. Diejenige, die ich gerade mit dem Differenzwolkenfilter von GIMP gemacht habe, war ursprünglich 14.583 Bytes, wurde aber nach der Rotation auf 23.638 Bytes geändert. Das ist ein Unterschied von über 9000 Bytes, was wie eine Menge zusätzlicher Daten erscheint, wenn wir nur über Metadaten sprechen.
@JamesSnell Also habe ich gerade denselben Test mit einem 512x512-Bild wiederholt und der Dateiunterschied beträgt 9.612 Bytes (beim ersten waren es 9.055). Da die erhöhte Dateigröße nicht proportional zur Vergrößerung der Abmessungen war, kann ich mit Sicherheit sagen, dass es sich tatsächlich um Metadaten handelt
Das scheint eine Menge zusätzlicher Metadaten zu sein. Ich würde nicht voreilig davon ausgehen, dass all diese zusätzlichen Daten Metadaten sind. Mir scheint, dass der Größenunterschied aufgrund von Metadaten fast eine Konstante sein sollte (bis auf wenige Bytes, um die Zeichenfolgendarstellung einiger Zahlen zu berücksichtigen).
Wenn Sie zusätzliche Informationen bereitstellen, die für die Frage relevant sind, bearbeiten Sie sie bitte in der Frage und nicht in den Kommentaren. Kommentare sind kurzlebig und können von Zeit zu Zeit bereinigt werden.
Was passiert, wenn Sie mit einem anderen (besseren) Bildbearbeitungswerkzeug drehen? Verdammt, ich wäre nicht überrascht, wenn WPV die Originalpixel speichern würde :-(
Es wäre hilfreich, die Originalversion Ihres Testbilds hochzuladen.
@CodesInChaos - ein Vorher-Nachher-Satz von Dateien würde es uns ermöglichen, die Frage vollständig zu beantworten. Aber sie müssten auf eine Weise bereitgestellt werden, die sie nicht verändert, also nicht die übliche imgur etc Route.
Könnte es nicht sein, dass Windows Picture Viewer das Bild mit einer geringeren Komprimierungsrate neu gespeichert hat?
Der Punkt ist, dass WPV das Bild bei der ersten Rotation erneut komprimiert, aber es komprimiert es so, dass, wenn die Größe ein Vielfaches von 8 nachfolgenden Rotationen ist, dies durch einfaches Anwenden von Byte-Transformationen auf den komprimierten Bytestream erfolgen kann. Meine Antwort adressiert das sogar richtig Wenn es heruntergestimmt wird, hat es die vollständige Erklärung (und es ist tatsächlich die einzig richtige Antwort)
Wie @DarioOO, aber versuchen, es klar zu machen. Verlustfrei bedeutet nicht gleich oder idempotent. Wenn man ein JPG neu codiert, könnte man eine bessere Komprimierung haben (Computer mit besserem Algorithmus/Speicher vs. Kamera), und dies gilt mit oder ohne Rotation. Verlustfrei bedeutet nur, dass das unkomprimierte Bild dasselbe ist, nichts über das ursprüngliche (komprimierte) Bild.
@GiacomoCatenazzi Theoretisch hast du Recht, aber in der Praxis macht die JPEG-Komprimierung dies fast unmöglich. Die verlustfreie 90-Grad-JPEG-Rotation erfolgt genau ohne Komprimierung durch Transposition komprimierter Daten. Wie ich Ihren Kommentar verstehe, sagen Sie, dass es immer eine Neukomprimierung gibt, nur nicht zu unterscheiden, während DarioOO sagt, dass es nur eine anfängliche Neukomprimierung in ein transponierbares Format gibt und von da an transponiert wird. Ich glaube, dass MCU-ausgerichtetes JPEG sofort transponierbar ist. betterjpeg.com/lossless-rotation.htm
MS-Komprimierungsbibliotheken sind schlecht und liefern oft weniger Komprimierung als andere Engines, die den "gleichen" Algorithmus verwenden.

Antworten (8)

Dies wird höchstwahrscheinlich durch die Entropiecodierung verursacht , die die letzte verlustfreie Stufe der JPEG-Komprimierung darstellt, nachdem die Bilddaten quantisiert wurden, um ihre Größe zu reduzieren.

Wenn ein JPEG-Bild verlustfrei gedreht wird, muss diese letzte verlustfreie Codierungsschicht rückgängig gemacht werden, die entpackten DCT-Koeffizienten herumgemischt werden, und dann müssen die gemischten Koeffizienten erneut entropiecodiert werden. Da die Effizienz der Entropiecodierungsschicht von der Reihenfolge der DCT-Koeffizienten innerhalb jedes Blocks abhängt, welche Drehung des Bildes sich ändert, sollte es nicht überraschen, dass die gedrehte Bilddatei einige Prozent kleiner oder größer als das Original sein kann.

Es gibt auch verschiedene Möglichkeiten, wie der Schritt der Entropiecodierung durchgeführt werden kann, sodass es durchaus möglich ist, dass die Dateigröße des exakt gleichen JPEG-Bildes je nach Software, die die Codierung durchführt, variieren kann. Zu den potenziellen Unterschieden zwischen Encodern gehören:

  • Wahl der arithmetischen Kodierung (selten, aber möglicherweise effizienter, früher patentiert) vs. Huffman-Kodierung (einfacher, Standard);
  • Wahl der sequentiellen (jeder 8x8-Pixel-Block wird einzeln codiert) gegenüber der progressiven (niedrigfrequente Komponenten aller Blöcke werden vor den höherfrequenten Komponenten codiert, normalerweise etwas kompakter) Codierungsreihenfolge;
  • Wahl zwischen der Verwendung der Standard-Huffman-Symboltabellen (schneller, einfacher, kann für sehr kleine Bilder effizienter sein) im Vergleich zu benutzerdefinierten Tabellen, die für jedes Bild optimiert sind (normalerweise effizienter für große Bilder, langsamer und komplexer zu codieren);
  • wenn benutzerdefinierte Huffman-Tabellen verwendet werden, können unterschiedliche Codierer möglicherweise unterschiedliche Tabellen für dieselben Bilddaten erzeugen;
  • Verschiedene Details auf niedriger Ebene des Codierungsprozesses selbst, wie z. B. ob und wann Neustartmarkierungen in den Datenstrom aufgenommen werden sollen, können auch zwischen Codierern variieren.

Außerdem enthalten die "JPEG-Dateien", mit denen normalerweise gearbeitet wird, tatsächlich JPEG-komprimierte Bilddaten, die in einen JFIF- oder Exif - Container verpackt sind, der die Bilddaten mit einem oder mehreren Metadatenblöcken kombiniert und seine eigenen Komplikationen einführt. Selbst wenn die Software, die das Bild dreht, keine wesentlichen Änderungen an den JFIF/Exif-Metadaten vornimmt, könnte eine einfache Neuanordnung der Daten die Dateigröße möglicherweise um einige Bytes beeinflussen.

Insbesondere die JFIF/Exif-Metadaten können ein oder mehrere Miniaturbilder des Vollbilds enthalten, und Software, die Bilder wirklich dreht, sollte die Miniaturbilder neu generieren (oder auch verlustfrei drehen!), damit sie der neuen Ausrichtung des Vollbilds entsprechen. Größe Bild. Dies allein könnte den beobachteten Größenunterschied leicht erklären.

Bei einem Unterschied von 9 KB (60 %) würde ich auf Thumbnails tippen.
JPEG mag zu einfach sein, als dass es sich für Encoder lohnen könnte, aber Video-Encoder wie x264 können tatsächlich die Fähigkeit des Einstiegs-Coders in Betracht ziehen, zu codieren, was sie als nächstes ausgeben, wenn sie Entscheidungen über den Kompromiss zwischen Rate und Verzerrung treffen. (dh zu entscheiden, wie viele Bits jede Alternative kosten könnte, und dies gegen den verlustbehafteten Fehler abzuwägen). Dies wird Trellis-Quantisierung genannt. Siehe Hinweise zur Implementierung der Trellis-Quantisierung in H.264 vom Autor von x264 (Loren Merritt); Er beginnt mit einer ziemlich einfachen Erklärung des Zwecks.
Wie auch immer, der JPEG-Codierer hat möglicherweise DCT-Koeffizienten so gewählt, dass sie mit dem Entropie-Codierer gut komprimiert werden können, sodass selbst ein optimaler Kompressor eine rotierte Version nicht so klein machen könnte. (Denn wenn Sie sie in eine andere Reihenfolge bringen, würden sie wahrscheinlich weniger gut komprimieren.) Dies wäre mit ziemlicher Sicherheit ein kleiner Effekt für JPEG, da jeder 8x8-Block separat codiert wird (Zurücksetzen des Zustands des Entropiecodierers, AFAIK). (I-Frames in h.264 verwenden eine Intra-Vorhersage, die von anderen Blöcken im selben Frame vorhergesagt wird, wodurch sie bei gleicher visueller Qualität kleiner als ein JPEG werden.)

Ich ging weiter und wiederholte das Experiment, um zu sehen, ob ich herausfinden konnte, was vor sich ging.

Verfahren

Ich habe ein zufälliges RGB-Bild mit 256 x 256 Pixeln mit dem Filter "Solid Noise" in GIMP (Filter > Rendern > Wolken > Solid Noise ...) mit den Standardeinstellungen (siehe unten) erstellt:

Geben Sie hier die Bildbeschreibung ein

Und das Ergebnis:

Geben Sie hier die Bildbeschreibung ein

Dann habe ich das Bild mit den Standardeinstellungen als JPEG gespeichert:

Geben Sie hier die Bildbeschreibung ein

Dann habe ich das Bild auf Windows übertragen und das Bild mit Windows Photo Viewer geöffnet, indem ich mit der rechten Maustaste auf das Bild im Datei-Explorer geklickt und Vorschau aus dem Menü gewählt habe. Dann drehte ich das Bild mit den Schaltflächen unten und speicherte das Bild, indem ich mit den Pfeiltasten zum nächsten Bild navigierte.

Für jeden der folgenden Tests habe ich mit einer Kopie des Originalbilds begonnen und es vor dem Speichern entsprechend oft gedreht (auf die Schaltfläche „Drehen“ geklickt). Hier sind die resultierenden Größen ( 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

Sofortige Beobachtungen

  • Windows Photo Viewer (WPV) erhöht die Größe dramatisch; die Höhe der Steigerung beträgt in diesem Test etwa das Vierfache!
  • Alle neuen Bilder werden ungefähr gleich groß, aber sie sind nicht identisch.
  • WPV kodiert oder speichert das Bild nicht neu, wenn es um ein Vielfaches von 360 Grad gedreht wird. (Der Zeitstempel, 11:27, ist der Zeitpunkt, an dem die Dateien zum ersten Mal kopiert wurden.)

Durch die Verwendung cmp -lvon Dateien, die identischen Inhalt haben sollten, können wir sehen, wo sich die Dateien unterscheiden.

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

Diese Dateien unterscheiden sich nur in vier Bytes (eigentlich in einem Zeitstempel), was bedeutet, dass WPV jedes Mal dasselbe tut; jetzt müssen wir nur noch herausfinden, was das ist.

Detaillierte Beobachtungen

Dafür habe ich JPEGsnoop verwendet, um zu sehen, was genau in den Bildern ist.

Da die Ausgaben ziemlich lang sind, habe ich sie als Kernstück verlinkt . Hier eine Zusammenfassung der Unterschiede:

  • GIMP verwendet nur ein APP0(JFIF) und COM(Kommentar) Segment für Metadaten. WPV lässt das APP0Segment unberührt, fügt dem Kommentar aber merkwürdigerweise ein Null-Byte hinzu (sodass er nullterminiert ist).

  • WPV fügt zwei APP1Segmente hinzu, nämlich Exif- und XMP-Metadaten. Diese Segmente sind 4286 bzw. 12726 Bytes groß. Zusammen machen sie fast die gesamte Zunahme der Dateigröße aus.

  • GIMP erzeugt ein progressives JPEG, während WPV ein (nicht progressives) Baseline-JPEG erzeugt. Aus diesem Grund hat das Bild von GIMP mehrere Scansegmente, während das WPV-Bild nur eines hat. Nach meiner Erfahrung ist das progressive Bild manchmal etwas kleiner.

  • GIMP verwendete 1 × 1-Chroma-Unterabtastung, während WPV 2 × 2-Unterabtastung verwendete. Dies lässt mich glauben, dass WPV keine "echte" verlustfreie Rotation verwendet, es sei denn, es ist irgendwie in der Lage zu erkennen, dass es sich um ein Schwarzweißbild handelt.

Um diese Probleme zu lösen, führte ich einen zweiten Test durch.

Verfahren

Ich folgte ähnlichen Schritten wie beim ersten Test. Ich habe ein zufälliges 256 × 256 RGB-Bild mit dem RGB-Rauschfilter (Filter > Nase > RGB-Nase ...) mit den folgenden Einstellungen erstellt:

Geben Sie hier die Bildbeschreibung ein

Hier ist das Ergebnis:

Geben Sie hier die Bildbeschreibung ein

Ich habe die Datei als JPEG mit den folgenden Einstellungen exportiert:

Geben Sie hier die Bildbeschreibung ein

Progressiv wurde ausgeschaltet, aber Subsampling ist immer noch auf 4:4:4 eingestellt (was ein anderer Name für 1×1-Subsampling ist). Die Qualität wird auf 98 erhöht.

Ich habe das Bild kopiert und die Kopie im Uhrzeigersinn gedreht; kopierte dann die gedrehte Version und drehte diese Kopie gegen den Uhrzeigersinn, sodass wir die Qualität zwischen dem Original und der WPV-verarbeiteten Kopie direkt vergleichen können.

Ergebnisse

-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

Obwohl der Zuwachs diesmal relativ gesehen geringer ausfällt (etwa 40 %), ist der absolute Zuwachs sogar noch größer – etwa 62 kB. Dies deutet darauf hin, dass WMV eine weniger effiziente Codierung verwendet.

Ich verwende ImageMagick , um die beiden Bilder zu vergleichen:

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

Zwischen dem Original und der gedrehten Kopie unterscheiden sich null Pixel . Selbst wenn WPV also keine "echte" verlustfreie Rotation verwendet, leistet es gute Arbeit. Ich vermute, ich weiß, was vor sich geht, und um es zu erklären, werde ich ein wenig in die Mathematik hinter der JPEG-Komprimierung eintauchen.

Der JPEG-Komprimierungsalgorithmus zerlegt ein Bild in 8×8-Pixel-Blöcke. Jeder dieser Blöcke wird dann einer diskreten Kosinustransformation (DCT) unterzogen . Die resultierenden DCT-Koeffizienten beschreiben den Block als eine Summe von Wellen unterschiedlicher Frequenz. Der Algorithmus "wirft" dann einige Informationen in den Hochfrequenzwellen weg, die Rauschen und sehr kleinen Details entsprechen. Der Decodierungsprozess kehrt die DCT um und fügt die gespeicherten Wellen zusammen, um den Block zurückzuerhalten.

Es ist möglich, die DCT-"Wellen" zu drehen, ohne die Transformation tatsächlich rückgängig zu machen und erneut durchzuführen (im Grunde verwandeln Sie alle horizontalen Wellen in vertikale Wellen und umgekehrt). Was meiner Meinung nach in WPV passiert, ist, dass das Bild tatsächlich dekodiert, gedreht und dann neu kodiert wird. Da die Größe unseres Bildes in beiden Dimensionen ein Vielfaches von 8 ist, entspricht während des Neucodierungsprozesses jeder der neuen Blöcke einem der ursprünglichen Blöcke. Da jeder Block keine Hochfrequenzkomponenten hat, wirft der Algorithmus keine Informationen weg und findet genau die richtigen DCT-Komponenten, die eine "echte" verlustfreie Rotation haben würde.

Zum Schluss schaue ich mir noch einmal die Bestandteile der JPEG-Dateien an. Die Ergebnisse sind wiederum als Gists verlinkt . Vergleich der beiden:

  • Das WPV-Bild enthält zusätzliche 4286+2 Byte Exif-Metadaten, 1 zusätzliches Byte im Kommentar und 12.726+2 Byte XMP-Metadaten. Dies sind insgesamt 17.017 Byte zusätzliche Metadaten. Wofür werden all diese Daten verwendet? Ich habe mit meinem bewährten Hex-Editor und einer Kopie der relevanten Standards in die Datei geschaut:

    • Exif-Metadaten sind wie ein TIFF-Bild strukturiert, das eine Reihe von Tags enthält (es gibt viel mehr Komplexität, aber ich überspringe es gleich). Die meisten Bytes im Exif-Segment sind in zwei identischen Tags mit der Tag-Nummer EA1C(59.932 dezimal) enthalten. Diese Tag-Nummer ist nirgendwo dokumentiert, was ich finden konnte. Beide Tags enthalten 2060 Bytes vom Typ "undefiniert", die alle Null-Bytes sind, mit Ausnahme der ersten sechs ( 1C EA 00 00 00 08). Ich habe keine Ahnung, was diese Tags sind, warum es zwei davon gibt und warum sie jeweils 2 kB groß sein müssen.

    • Die XMP-Metadaten sind eigentlich ein vollständiges eingebettetes XML-Dokument mit Namensräumen und langen UUIDs, das nur den WPV-Versionsstring enthält (der bereits in den Exif-Metadaten enthalten war). Das macht aber nur etwa 400 Bytes aus. Der Rest des Segments besteht aus 122 Wiederholungen von 100 Leerzeichen gefolgt von einem Zeilenumbruch . Das sind über 12.000 Bytes völlig verschwendeter Speicherplatz.

  • Wie beim vorherigen Test verwenden sowohl GIMP als auch WPV dieselben DCT-Quantisierungstabellen. Dies bedeutet, dass sie genau die gleichen DCT-Koeffizienten berechnen sollten, weshalb die Bilder genau gleich sind. Ich bin mir nicht sicher, ob WPV zufällig dieselben Quantisierungstabellen verwendet oder ob es die Tabellen aus der Eingabe kopiert.

  • Im Gegensatz zum vorherigen Test verwendet WPV diesmal 1×1-Unterabtastung, sodass möglicherweise tatsächlich erkannt wird, dass es sich um ein Farbbild handelt (oder zumindest höhere Abtastwerte erforderlich sind, um das Bild verlustfrei neu zu codieren).

  • GIMP und WPV verwenden unterschiedliche Huffman-Tabellen (Teil des Entropiecodierungsschritts). Die Tabellen für WPV sind insgesamt um 279 Bytes größer und enthalten in einem Fall 7 mal so viele Codes.

    Wenn wir uns die Statistiken von JPEGsnoop ansehen, können wir sehen, dass einige dieser Codes selten verwendet werden. Beispielsweise werden in der ID: 1, Class: ACTabelle von den 119 definierten 16-Bit-Codes nur 23 tatsächlich verwendet. Insgesamt ist das eigentliche Scansegment in der WPV-Version um 28,5 % größer.

Zusammenfassung

  • WPV führt möglicherweise keine "echten" verlustfreien Rotationen durch, aber die Rotationen scheinen praktisch verlustfrei zu sein.

  • Die zusätzliche Größe ist teilweise auf eine feste Menge hinzugefügter Metadaten und teilweise auf eine weniger effiziente Entropiecodierung zurückzuführen.

Versionsinformation:

  • Betriebssystem (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
    
  • Betriebssystem (Windows):

    Geben Sie hier die Bildbeschreibung ein

  • GIMP (Linux): 2.8.14 (aus Paket gimp, Version 2.8.14-1+deb8u1)

    Geben Sie hier die Bildbeschreibung ein

  • Window Photo Viewer (gemäß Bildmetadaten):

    Microsoft Windows Photo Viewer 10.0.10586.0
    

BEARBEITEN : Diese Antwort wurde gepostet, bevor ich wusste, dass die Dateien um etwa 9 KiB an Größe zugenommen hatten (9055 Byte für das 256 × 256-Bild, 9612 KiB für das 512 × 512-Bild).

Als Sie das Bild zum ersten Mal gedreht haben, hat Windows Picture Viewer aller Wahrscheinlichkeit nach eines (oder beides) der folgenden Dinge getan:

  1. Ein EXIF-Tag hinzugefügt, das nicht im ursprünglichen JPEG-Bild enthalten war (möglicherweise das Orientierungs-Tag);
  2. Geänderte/hinzugefügte Informationen zu einem bereits vorhandenen Tag (vielleicht Verarbeitungssoftware- oder Bildsoftware-Tags).

Dadurch erhöhte sich die Dateigröße aufgrund des zusätzlichen EXIF-Tags (und/oder zusätzlicher Daten zu bestehenden Tags).

Nachfolgende Rotationen haben die Dateigröße nicht erhöht, da alle Tags und/oder Tag-Daten, die WPV hinzugefügt/geändert hätte, bereits vorhanden waren. Nur der Wert des Orientierungs-Tags hat sich geändert (und vielleicht auch die Tag-/Zeit-Tag-Werte).


BEARBEITEN : Es ist fast sicher, dass diese Erklärung nicht etwa 9 KiB zusätzlicher Daten in der Datei berücksichtigen kann. Ohne andere Gründe für die Größenzunahme würde diese Erklärung ferner erwarten, dass die Größenzunahme mehr oder weniger konstant wäre (modulo einige Längenunterschiede zwischen Zeichenfolgendarstellungen numerischer Daten, wahrscheinlich einige Bytes). Das ist offensichtlich nicht das, was hier passiert, zumindest nicht die vollständige Erklärung.

Und ein EXIF-Tag wird 9kB beanspruchen? Nun, das ist zumindest einfach zu testen - lassen Sie das OP EXIF ​​oder andere Tags aus dem gedrehten Bild löschen und sehen Sie, wie sich die Dateigröße ändert.
@CarlWitthoft die 9kB sind neue Informationen. Bearbeitung, um das zu erwähnen.

Ohne Reverse Engineering des JPEG-En/Decoders ist es unmöglich, dies mit Sicherheit zu sagen. Es gibt tatsächlich eine Reihe von JPEG-Standards, und entgegen der landläufigen Meinung können nicht alle ohne Neucodierung geändert werden.

Es ist möglich, dass die erste Speicherung ein verlustbehaftetes Umschreiben in die bevorzugte JPEG-Variante ist und die nachfolgenden Rotationen eine einfache Metadatenoptimierung oder eine Operation direkt an der DCT-Tabelle sind (was für einige Codierungsschemata möglich ist).

Die Erhöhung der Dateigröße kann auch einige zusätzliche Metadaten enthalten, obwohl 9k viel zu sein scheint, ist es möglich. Die Erhöhung kann auch durch das Hinzufügen eines Miniaturbilds erklärt werden, das in der Ausgabe von GIMP möglicherweise nicht vorhanden war. Möglicherweise können wir weitere Informationen direkt aus den Dateien entnehmen (vor WPV und danach).

In jedem Fall ist der Versuch, verlustfrei mit JPEG zu arbeiten, wirklich ein Kinderspiel, da es nur bei bestimmten Bildgrößen nützlich ist, nicht alle Decoder und Encoder identisch sind und diese Editoren direkt mit dem JPEG-Inhalt arbeiten müssen, auf den Sie sich nicht verlassen können der Fall ... Nur weil es jetzt so ist, heißt das nicht, dass es auch in Zukunft so bleiben wird.

Ihre bessere Wette ist es, mit einem verlustfreien Format zu arbeiten und den Schmerz vollständig zu vermeiden.

Ich bin überhaupt nicht davon überzeugt, dass rotierende JPEG-Daten überhaupt zu einer Neucodierung führen sollten.
Hängt davon ab, ob Sie ein Programmierer sind oder nicht ... Ich vermute, Sie sind es nicht. Sie müssten speziell nach dieser Optimierung suchen, um diese minimale Änderung vorzunehmen, da sonst ein Speichervorgang mit der unkomprimierten Bitmap beginnen würde.
Aus der verknüpften Frage geht hervor, dass Windows Photo Viewer JPEGs verlustfrei dreht.
Aber unter welchen Umständen... Das ist der Teil, den wir nicht wissen.
@James Ich bin kein Low-Level-Programmierer, obwohl ich im Fernsehen spiele :-) . Das OP stellte einen Link zu einer genauen Beschreibung bereit, wann eine Neucodierung erfolgen würde und wann nicht. Ich hatte aus dieser Diskussion gefolgert, dass er nur um $\frac{\pi}{2}$ rotiert hatte. Ich stimme zu, dass eine willkürliche Winkeldrehung eine Neucodierung verursacht und im Übrigen zu einem Informationsverlust führt, es sei denn, das X-by-Y-Bild ist in einen Bereich eingebettet, der mindestens so groß wie die Hypotenuse ist.
Es geht nicht darum, was mathematisch machbar ist. Es geht jedoch darum, was der Code tatsächlich tut. Was das OP sieht, ist, dass Iteration 1 eine Änderung der Dateigröße verursacht, nachfolgende Iterationen jedoch nicht. Es gibt Gründe dafür, und ich werde gleich eine Bearbeitung vornehmen, um zu erklären, was passieren kann.
Die Ursache für die verlustfreie Drehung (was ein schlechter Begriff ist; besser wäre reversibel ) liegt vor, wenn die Abmessungen des Bildes Vielfache von 8 oder 16 sind, was die minimale komprimierbare Einheit ist . Wenn ein JPEG keine partiellen MCUs enthält, kann es gedreht/gespiegelt werden, ohne dass die DCT-Datenblöcke geändert werden. In diesem Fall gibt es überhaupt keine Neucodierung, sondern es wird lediglich eine Matrix von Indizes auf diese Blöcke geändert.
@scottbb - das gilt nur für bestimmte Codierungsmethoden innerhalb der JPEG-Spezifikation. und es verlässt sich auf die Software, die nach dieser Optimierung sucht. Wir wissen nur (a) ja, es ist unter bestimmten Umständen möglich und (b) dass wir nicht genau wissen, was diese Anwendung tut ...
Wir sind ziemlich sicher, dass wir wissen , dass WPV bei Bildern mit Dimensionen, die ein Vielfaches von 8/16 sind, umkehrbar rotiert. Siehe @Tristans Kommentar zu Matt Grums Antwort auf die im OP verlinkte Frage. Tristan arbeitete im WPV-Team bei Microsoft und bestätigt im Grunde.
@scottbb - nur für die 2. und nachfolgende. Wir wissen NICHT, was mit dem ersten passiert, und das versuchen wir hier herauszufinden.

Eine verlustfreie JPEG-Rotation ist ohne Einführung von Randartefakten nur möglich, wenn die Bildabmessungen ein Vielfaches der Blockgröße sind (typisch [/immer?] 8). Siehe die Manpage von jpegtran (sorry, ich habe keinen guten kanonischen Link dafür; Sie können ihn gerne bearbeiten, wenn Sie einen finden) für Details darüber, worum es geht:

Die Transponierungstransformation hat keine Einschränkungen hinsichtlich der
Bildabmessungen. Die anderen Transformationen arbeiten ziemlich seltsam, wenn die Bildabmessungen kein Vielfaches der iMCU-Größe (normalerweise 8 oder 16 Pixel) sind, weil sie nur ganze Blöcke von DCT-Koeffizientendaten in der gewünschten Weise transformieren können.

Das Standardverhalten von jpegtran beim Transformieren eines Bildes mit ungerader Größe
soll die exakte Umkehrbarkeit und mathematische
Konsistenz des Transformationssatzes bewahren. Wie bereits erwähnt, ist die Transponierung in der
Lage, den gesamten Bildbereich zu spiegeln. Die horizontale Spiegelung lässt jede partielle iMCU-Spalte am rechten Rand unberührt, kann aber alle Zeilen des Bildes spiegeln. In ähnlicher Weise lässt vertikales Spiegeln jede partielle iMCU-Zeile am unteren Rand unberührt, kann aber alle Spalten umdrehen. Die anderen Transformationen können als Sequenzen von Transponierungs- und Flip-Operationen aufgebaut werden; aus Konsistenzgründen werden ihre Aktionen auf Kantenpixel so definiert, dass sie die gleichen sind wie das Endergebnis der entsprechenden Transponierungs- und Spiegelungssequenz.

Für die praktische Verwendung ziehen Sie es möglicherweise vor, alle nicht transformierbaren Kantenpixel zu verwerfen,
anstatt einen seltsam aussehenden Streifen entlang der
rechten und/oder unteren Kante eines transformierten Bildes zu haben. Fügen Sie dazu den Schalter -trim hinzu:

Ich vermute, dass der Windows Photo Viewer dieses Problem vermeidet, indem er eine Dekomprimierung und eine Neukomprimierung in extrem hoher Qualität durchführt, um ein verlustfreies Verhalten zu simulieren, wenn die Bildabmessungen kein Vielfaches von 8 sind, anstatt tatsächlich eine verlustfreie Drehung durchzuführen. Ein gutes Dienstprogramm würde nur wirklich verlustfrei, Artefakte und alles machen oder ein paar Pixel auslassen, anstatt die Qualität des gesamten Bildes zu ruinieren (und die Dateigröße zu erhöhen).

irrelevant für ein 256x256-Bild.
Ich habe mich verlesen und dachte, das Problem betreffe die 257x257-Version.

Ich habe keine eindeutige Antwort, aber einige mögliche Theorien, warum das passiert ist. Einige Dateitypen funktionieren so, dass zwei verschiedene Codes für ein Bild dieses Dateityps nicht unbedingt unterschiedliche Bilder erzeugen. Beispielsweise funktioniert der PNG-Dateityp auf diese Weise, weil er einen transparenten Hintergrund zulässt, aber ein Bild mit transparentem Hintergrund und eines, das dasselbe ist, außer dass derselbe Hintergrund weiß ist, genau gleich angezeigt wird. Eine Bilddatei gilt als komprimiert, wenn sie weniger als 3 Byte Speicherplatz pro Pixel benötigt. Ich glaube, dass außer denen mit transparentem Hintergrund keine zwei PNG-Dateien genau das gleiche Bild erzeugen. Wann immer Sie ein Bild als PNG speichern, wird es in einen Code konvertiert, der das Originalbild generiert, und mit Ausnahme sehr ungewöhnlicher Bilder wie eines, bei dem jedes Pixel eine zufällige Farbe aller 2^24 Farben ist, Der Code benötigt weniger Speicher als 3 Bytes pro Pixel, sodass das Speichern als PNG eine verlustfreie Komprimierung ist. Andererseits können, um Speicherplatz zu sparen, nur bestimmte Bilder durch den Code einer JPEG-Bilddatei erzeugt werden. Es gibt wahrscheinlich mehr als einen JPEG-Dateityp und ich weiß nicht, ob einer von ihnen die Eigenschaft hat, dass zwei verschiedene Bilder dieses Dateityps genau dasselbe Bild erzeugen können. Ich gehe davon aus, dass Sie ein paar Mal ein Bild gedreht und dann als JPEG gespeichert haben, und erklären, was passiert ist, unter der Annahme, dass Sie dies getan haben, von dem ich nicht weiß, ob es stimmt. Eine Drehung, die Sie durchgeführt haben, ist verlustfrei, wenn es eine Möglichkeit gibt, genau den gleichen Bilddateicode wie vor dem Drehen und Speichern wiederherzustellen. Möglicherweise haben Sie nicht Recht, dass Sie wirklich eine verlustfreie Rotation durchgeführt haben. Wenn es wirklich verlustfrei wäre,

Die Gründe dafür sind ein paar

Die Art und Weise, wie Bilder codiert und komprimiert werden, ändert die Größe einfach aufgrund des Komprimierungsalgorithmus. Sie können dies testen, indem Sie es als Bitmap speichern und dann drehen. In diesem Format oder einem anderen Rohformat sollte die Größe gleich bleiben. Wenn dies nicht der Fall ist, fügt das Programm, das das Bild speichert, neue Daten hinzu, möglicherweise einige Metadaten oder so etwas.

Aber warum drehen Sie ein JPEG 20 Mal?

Wenn Sie den Link in der ursprünglichen Frage lesen, zumindest für Windows Picture Viewer , wenn die Abmessungen eines JPEGs ein Vielfaches von 8 sind, dann sind Drehungen von JPEGs in WPV verlustfreie Transformationen. Eine einfache Möglichkeit, dies zu testen, besteht darin, das Bild viermal zu drehen (was zu derselben Ausrichtung wie das Original führt) und eine einfache Bildsubtraktion Pixel für Pixel durchzuführen.
@scottbb Dies ist nicht unbedingt nur ein Problem mit dem Windows Picture Viewer. Alles, was ein verlustbehaftetes Format dreht, muss die Komprimierung neu berechnen. Das Drehen eines Bildes in Vielfachen von 8 bedeutet, dass alles in 8-Bit-Wörter passt und möglicherweise nicht auf eine Weise komprimiert wird, die Artefakte hinzufügt. Dies basiert auf der Funktionsweise des Algorithmus und ist in dem verwendeten Programm implementiert.

Aufgrund der Art und Weise, wie die Komprimierung von Bildern funktioniert . Jedes Format wie PNG oder JPG behält im Allgemeinen die Dateigröße nach der Drehung nicht bei.

Für den Komprimierer ist das gedrehte Bild nur ein anderes Bild. Aufgrund der Funktionsweise der Komprimierungsheuristik gibt es keine Garantie, dass ein gedrehtes Bild gleich komprimiert wird .

Wenn die Komprimierung natürlich verlustfrei ist, wenn Sie das Bild 4 Mal drehen, ist das Bild beim 4. Mal wieder dasselbe (gedreht, bis es wie das Original geneigt wird): In diesem Fall sollte es wieder dieselbe komprimierte Größe haben, wenn nicht dann es liegt an einem der folgenden Gründe :

  • Metadaten hinzugefügt: Das Programm hat aus irgendeinem Grund einen Textabschnitt hinzugefügt
  • Compressor geändert: Das Programm kann sich dafür entscheiden, das Bild einfach als Original neu zu speichern, wenn es keine Änderungen gibt, aber wenn Sie eine Änderung vornehmen (sogar 4 Drehungen um 90 Grad), kann es entscheiden, das Bild erneut mit seinem eigenen neu zu komprimieren Kompressor (das Programm weiß nicht mehr, es ist immer noch das gleiche Bild).
  • Im Allgemeinen liefert derselbe Kompressor (libPNG oder libJPG) sehr unterschiedliche Ergebnisse über verschiedene Implementierungen, verschiedene Versionen derselben Bibliothek und mit unterschiedlichen Komprimierungsparametern (auch Betriebssystem und Compiler machen hier manchmal einen Unterschied).

Die Bildkomprimierung funktioniert durch Komprimieren von Bildern in 4x4- oder andere Größenblöcke. Im Allgemeinen sieht ein Komprimierer ein gedrehtes Bild als ein anderes Bild, da jedoch ein komprimierter Pixelblock nur eine lineare Zerlegung ist, ist es möglich, wenn die Blöcke auf dem Bild gleich sind, einfach die linearen Zerlegungsmatrizen zu transponieren/spiegeln, wobei effektiv dieselben beibehalten werden Qualität:

Beachten Sie, dass dies pro Feature implementiert werden muss , und das erklärt auch die anfängliche Vergrößerung => bei der ersten Rotation wird nur versucht, das Bild in rotierbaren Blöcken zu komprimieren:

  • Gelingt dies nicht: Die Bildqualität lässt nach
  • Wenn es erfolgreich ist, wird die Größe nur einmal erhöht, dann behält jede Drehung die gleiche Qualität.

  • Diese Operation ist nur erfolgreich, wenn das Bild aus gleichen Teilen besteht. (Größe des Bildes ist ein Vielfaches der Chunk-Größe).

Die scottbb-Antwort ist falsch und Sie können einen einfachen Test durchführen:

  • Öffnen Sie das Originalbild: Screenshot
  • Drehen Sie das Bild viermal mit WPV: Machen Sie einen Screenshot davon
  • Vergleichen Sie die 2 Screenshots

Sie werden sehen, dass sich das Bild geändert hat (es wird bei der ersten Drehung neu komprimiert). Diese Änderung ist jedoch zeitlich begrenzt, Sie können sie jetzt ohne Qualitätsverlust erneut drehen (wenn das Bild eine Größe hat, die ein Vielfaches von 8 ist).

Um OP direkt zu beantworten:

Ich weiß, es rotiert verlustfrei

Nicht, es dreht sich nicht verlustfrei, es verliert mindestens einmal an Qualität (bei der ersten Drehung: weil es zuerst so komprimiert werden soll, dass es rotiert werden kann), dann behält es seine Qualität.

Die Frage betrifft die verlustfreie Rotation, sodass eine erneute Komprimierung vermieden wird.
Ich programmiere einen Grafikeditor, damit ich weiß, was ich sage, wenn die Datei gespeichert ist => sie ist komprimiert. Was der Datei zumindest hinzugefügt wird, sind "Rotations"-Informationen.
Ich weiß, was ich sage und habe sogar einen Bildkompressor implementiert. Es ist möglich, wenn Sie dies nur für die Drehung implementieren (was bedeutet, dass Sie wissen, dass die Drehung die einzige Änderung am Bild ist), im Allgemeinen ist dies nicht möglich. Scheint, dass Entwickler von Windows Photo Editor diesen Trick gemacht haben
OP fragte nicht nach dem allgemeinen Fall, sondern genau nach dieser einen bestimmten Software und diesem einen bestimmten Fall, der dies tut. Ihre Antwort ist nicht falsch, sie beantwortet nur eine andere Frage als die, die OP gestellt hat.
Nein, es antwortet. Lies es nochmals. Ich habe das vor einiger Zeit bearbeitet.
Erste 3 Sätze noch zu einer anderen Frage: "wie Komprimierung von Bildern funktioniert" - es gibt keine Komprimierung bei verlustfreier Rotation. "Zum Kompressor das gedrehte Bild" - wieder wird der Kompressor nicht aufgerufen. "wenn die Komprimierung verlustfrei ist" - die Komprimierung ist verlustbehaftet. Die Rotation ist verlustfrei. Nun, so weit bin ich bereit, dieses Argument zu gehen. Ich verstehe Ihren Standpunkt, ich stimme ihm zu, aber er ist hier völlig fehl am Platz. Übrigens bin ich auch Programmierer und habe meinen Anteil am Lesen und Schreiben von Rohdateien geleistet.
Das scheinst du zu persönlich zu nehmen. ES IST KEINE VERLUSTLOSE ROTATION: Lesen Sie einfach das kleine Experiment und machen Sie es selbst. Es zeigt im Grunde, dass Ihr letzter Kommentar falsch ist. Uu Sie sind vielleicht sogar ein Programmierer, aber ich glaube nicht, dass Sie jemals einen Bildkomprimierer codiert haben (auch nicht einen einfacheren).
Es tut mir leid, welches Experiment kann ich machen, um es zu zeigen? Weil in der verknüpften Frage ein Experiment durchgeführt wurde. Interpretiere ich die Ergebnisse falsch?
Ich habe ein Bild in Paint erstellt, es 4 Mal gedreht und es ist identisch, aber die Größe ist trotzdem von 1,6 auf 8,1 KB gestiegen. Binary diff zeigt, dass Bilddaten unberührt waren, es ist nur ein riesiger Teil von Metadaten in <?xpacketTags.
PAint-Bild ist kein guter Kandidat uu Ich habe gerade das Experiment mit einem echten Foto gemacht. Haben Sie ein anderes Bild verwendet? Entschuldigung, aber welche Windows-Version hast du?
Ich habe einen Screenshot gemacht, ihn in Paint eingefügt und auf 128 x 128 beschnitten. Es sieht so aus, als ob derselbe Teil der Kerndaten wiederholt wird, aber die rotierte Version hat einen riesigen Teil von fast leeren <?xpackethinzugefügt. Ich habe hier kein richtiges binäres Diff, also kann ich es nicht sagen. Nachdem ich beide auf verexif.com hochgeladen hatte, kamen sie identisch zueinander zurück, aber nicht zum Original. Aber wie gesagt, ich vergleiche sie von Hand im Hexeditor, also habe ich wahrscheinlich viel verpasst. Windows 8.1
Wenn die Abmessungen eines JPEGs gleichmäßig durch 8 (oder 16 mit Subsampling) teilbar sind, kann es verlustfrei in Schritten von 90 Grad gedreht werden . Der Schlüssel ist, es nicht bis zu RGB zu decodieren, sondern direkt mit den DCT-Koeffizienten zu arbeiten. Es ist eine spezialisierte Funktion, die nicht oft in einem allgemeinen Bildeditor enthalten ist. Siehe zum Beispiel en.wikipedia.org/wiki/Libjpeg#jpegtran . Wenn Sie Ihr Experiment mit Windows Photo Viewer wie in der Frage angegeben durchgeführt haben, würden Sie feststellen, dass es tatsächlich verlustfrei ist.