Je viens de rencontrer la chose suivante: j'ai mis plusieurs copies identiques d'une image png dans un dossier, puis j'ai essayé de compresser ce dossier avec les méthodes suivantes:
tar czf folder.tar.gz folder/
tar cf folder.tar folder/ && xz --stdout folder.tar > folder.tar.xz
(celui-ci fonctionne bien pour des images identiques, cependant pour des images similaires le gain est nul)zip -r folder.zip folder/
Lorsque j'ai vérifié la taille du .tar.gz
, .tar.xz
, .zip
je me suis aperçu qu'il est presque le même que celui de folder/
.
Je comprends qu'une image png elle-même peut avoir un niveau de compression élevé et ne peut donc pas être compressée davantage. Cependant, lors de la fusion de nombreuses images png similaires (dans ce cas, même identiques) dans une archive, puis en compressant l'archive, je m'attends à ce que la taille requise diminue considérablement. Dans le cas d'images identiques, je m'attendrais à une taille à peu près la taille d'une seule image.
data-compression
un invité
la source
la source
.bmp
), le fichier tar.gz devrait pouvoir profiter de la similitude. (Au moins si la similitude est que beaucoup de pixels sont identiques)Réponses:
Jetez un œil au fonctionnement des algorithmes de compression. Au moins, ceux de la famille Lempel-Ziv (
gzip
utilise LZ77 ,zip
semble - t- il aussi le plus souvent , etxz
utilise LZMA ) se compressent quelque peu localement : les similitudes éloignées les unes des autres ne peuvent pas être identifiées.Les détails diffèrent entre les méthodes, mais en fin de compte, au moment où l'algorithme atteint la deuxième image, il a déjà «oublié» le début de la première. Etc.
Vous pouvez essayer de modifier manuellement les paramètres de la méthode de compression; si la taille de la fenêtre (LZ77) resp. la taille des blocs / morceaux (méthodes ultérieures) est au moins aussi grande que deux images, vous verrez probablement une compression supplémentaire.
Notez que ce qui précède ne s'applique vraiment que si vous avez des images identiques ou des images non compressées presque identiques . S'il y a des différences, les images compressées peuvent ne pas se ressembler en mémoire. Je ne sais pas comment fonctionne la compression PNG; vous souhaiterez peut-être vérifier manuellement les représentations hexadécimales des images que vous avez pour les sous-chaînes partagées.
Notez également que même avec des paramètres modifiés et une redondance à exploiter, vous n'obtiendrez pas la taille d'une image. Des dictionnaires plus grands signifient une plus grande taille de mot de code, et même si deux images sont exactement identiques, vous devrez peut-être coder la seconde en utilisant plusieurs mots de code (qui pointent dans la première).
la source
Pourquoi cela se produit. Il y a en fait deux effets différents qui se produisent ici:
Chaque fichier compressé indépendamment. Certains programmes d'archivage - y compris zip - compressent chaque fichier indépendamment, sans mémoire d'un fichier à un autre. En d'autres termes, chaque fichier est compressé séparément, puis les fichiers compressés sont concaténés dans une archive.
Mémoire à court terme. Certains programmes d'archivage peuvent utiliser des informations sur un fichier pour mieux compresser le fichier suivant. Ils concaténent efficacement les fichiers, puis compressent le résultat. C'est une amélioration.
Voir aussi la réponse de Nayuki pour plus de discussion à ce sujet.
Cependant, il y a un deuxième problème. Certains schémas de compression - y compris zip, gzip et bzip2 - ont une mémoire limitée. Ils compressent les données à la volée et se souviennent des 32 Ko de données passés, mais ils ne se souviennent de rien des données qui se sont produites beaucoup plus tôt dans le fichier. En d'autres termes, ils ne peuvent pas trouver de données en double si les doublons se produisent à plus de 32 Ko d'intervalle. Par conséquent, si les fichiers identiques sont courts (plus courts que 32 Ko environ), l'algorithme de compression peut supprimer les données dupliquées, mais si les fichiers identiques sont longs, l'algorithme de compression est arrosé et devient sans valeur: il ne peut détecter aucun des éléments suivants: le doublon dans vos données. (Bzip se souvient des 900 derniers Ko environ des données, au lieu de 32 Ko.)
Tous les algorithmes de compression standard ont une taille de mémoire maximale, au-delà de laquelle ils ne parviennent pas à détecter les modèles ... mais pour certains, ce nombre est beaucoup plus grand que d'autres. Pour Bzip, c'est quelque chose comme 900 Ko. Pour xz, c'est quelque chose comme 8 Mo (avec les paramètres par défaut). Pour 7z, c'est quelque chose comme 2 Go. 2 Go est plus que suffisant pour reconnaître les copies dupliquées de fichiers PNG (qui sont généralement beaucoup plus petites que 2 Go). De plus, 7z essaie également d'être intelligent pour placer des fichiers susceptibles d'être similaires les uns à côté des autres dans l'archive, pour aider le compresseur à mieux fonctionner; tar n'en sait rien.
Voir aussi la réponse de Raphaël et la réponse de Nayuki pour plus d' explications de cet effet.
Comment cela s'applique à votre paramètre. Pour votre exemple spécifique, vous travaillez avec des images PNG. Les images PNG sont elles-mêmes compressées, vous pouvez donc considérer chaque fichier PNG comme une séquence d'octets d'aspect aléatoire, sans motif ni duplication dans le fichier. Il n'y a rien à exploiter pour un compresseur s'il regarde une seule image PNG. Ainsi, si vous essayez de compresser un seul fichier PNG (ou de créer une archive zip / tar / ... contenant un seul fichier PNG), vous n'obtiendrez aucune compression.
Voyons maintenant ce qui se passe si vous essayez de stocker plusieurs copies du même fichier PNG:
Petits fichiers. Si le fichier PNG est très petit, tout sauf le zip fonctionnera très bien. Zip échouera de façon spectaculaire: il comprime chaque fichier indépendamment, il n'a donc aucune chance de détecter la redondance / duplication entre les fichiers. De plus, comme il essaie de compresser chaque fichier PNG, il n'obtient aucune compression; la taille d'une archive zip sera énorme. En revanche, la taille d'une archive tar (qu'elle soit compressée avec gzip, bzip2 ou xz) et une archive 7z sera petite, car elle stocke essentiellement une copie du fichier et remarque ensuite que les autres sont toutes identiques - elles bénéficient de conserver la mémoire d'un fichier à un autre.
Fichiers volumineux. Si le fichier PNG est volumineux, alors seulement 7z fonctionne bien. En particulier, zip continue d'échouer de façon spectaculaire. De plus, tar.zip et tar.bzip2 échouent gravement, car la taille du fichier est plus grande que la fenêtre de mémoire du compresseur: lorsque le compresseur voit la première copie du fichier, il ne peut pas la réduire (car il a déjà été compressé ); au moment où il commence à voir le début de la deuxième copie du fichier, il a déjà oublié les séquences d'octets vues au début du premier fichier et ne peut pas établir la connexion que ces données sont en fait un doublon.
En revanche, tar.xz et 7z continuent de bien fonctionner avec plusieurs copies d'un grand fichier PNG. Ils n'ont pas la limitation "petite taille de mémoire" et sont capables de remarquer que la deuxième copie du fichier est identique à la première copie, donc il n'est pas nécessaire de le stocker une deuxième fois.
Que pouvez-vous y faire? Utilisez 7z. Il a un tas d'heuristiques qui aideront à détecter des fichiers identiques ou similaires et à compresser très bien dans ce cas. Vous pouvez également regarder lrzip avec la compression lzop.
Comment puis-je savoir? J'ai pu le vérifier en essayant quelques expériences avec 100 copies d'un fichier contenant des octets aléatoires. J'ai essayé 100 copies d'un fichier de 4 Ko, 100 copies d'un fichier de 1 Mo et 100 copies d'un fichier de 16 Mo. Voici ce que j'ai trouvé:
Comme vous pouvez le voir, le zip est horrible, quelle que soit la taille de votre fichier. 7z et xz sont tous les deux bons si vos images ne sont pas trop grandes (mais xz sera fragile et dépendra de l'ordre dans lequel les images seront placées dans l'archive, si vous avez des doublons et des non-doublons mélangés ensemble). 7z est sacrément bon, même pour les gros fichiers.
Les références. Cela est également bien expliqué dans un tas de messages sur Super User. Regarde:
la source
tar
puis compressées avecxz
(ce qui fonctionnait très bien pour des images identiques) mais en cas d'images similaires le gain est nul. J'ai essayé avec 71 images ayant chacune une taille de ~ 831 Ko.Tout d'abord, notez que le format d'image PNG est essentiellement des pixels RVB bruts (avec un certain filtrage de la lumière) poussés à travers le format de compression DEFLATE. De manière générale, les fichiers compressés (PNG, JPEG, MP3, etc.) ne verront aucun avantage à être à nouveau compressés. Donc, pour des raisons pratiques, nous pouvons traiter votre fichier PNG comme des données aléatoires incompressibles pour le reste de l'expérience.
Deuxièmement, notez que les formats ZIP et gzip utilisent également le codec DEFLATE. (Cela expliquerait pourquoi le zippage par rapport au gzipping d'un seul fichier produira essentiellement la même taille de sortie.)
Permettez-moi maintenant de commenter chaque cas de test individuellement:
tar czf folder.tar.gz folder/
Cela crée un fichier TAR (non compressé) qui concatène tous vos fichiers PNG identiques (avec une petite quantité de métadonnées et de remplissage ajoutés). Ensuite, ce fichier unique est envoyé via le compresseur gzip pour créer un fichier de sortie compressé.
Malheureusement, le format DEFLATE ne prend en charge qu'une fenêtre de dictionnaire LZ77 de 32 768 octets. Donc, même si le TAR contient des données répétitives, si votre fichier PNG est supérieur à 32 Ko, le compresseur DEFLATE ne peut certainement pas se souvenir des données suffisamment loin pour profiter du fait que des données identiques sont récurrentes.
En revanche, si vous réessayez cette expérience avec, par exemple, un fichier PNG de 20 Ko dupliqué 10 fois, il est très probable que vous obtiendrez un fichier gzip à peine supérieur à 20 Ko.
tar cf folder.tar folder/ && xz --stdout folder.tar > folder.tar.xz
Cela crée un fichier TAR comme avant, puis utilise le format xz et le compresseur LZMA / LZMA2. Je n'ai pas pu trouver d'informations sur LZMA dans cette situation, mais à partir de 7-Zip pour Windows, je sais qu'il peut prendre en charge les grandes tailles de fenêtre de dictionnaire (par exemple 64 Mio). Il est donc possible que vous utilisiez des paramètres sous-optimaux et que le codec LZMA ait pu réduire le fichier TAR à la taille d'un seul fichier PNG.
zip -r folder.zip folder/
Le format ZIP ne prend pas en charge les archives "solides"; c'est-à-dire que chaque fichier est compressé indépendamment. Nous avons supposé que chaque fichier était incompressible. D'où le fait que chaque fichier est identique ne peut pas être exploité, et le fichier ZIP sera aussi gros que la concaténation directe de tous les fichiers.
la source
xz
par défaut s'exécute enxz -6
mode, qui utilise un dictionnaire LZMA2 de 8 MiB . Je n'ai pas pu trouver immédiatement dans la page de manuel disponible sur mon système Debian quelle est la taille de fenêtre par défaut pour le compresseur.tar czf folder.tar.gz folder/ && xz --stdout folder.tar.gz > folder.tar.gz.xz
sans aucun effet (ce qui est logique selon ce que vous avez expliqué). Je suppose que je me suis un peu perdu dans tous ces trucs de compression: D Lors de l'utilisation,tar cf folder.tar folder/ && xz --stdout folder.tar > folder.tar.xz
je me retrouve avec un peu plus que la taille d'une image (ce qui est également logique en fonction de la taille de fenêtre de dict par défaut de 64 Mio). J'ai mis à jour ma question en conséquence. Merci!tar -> gzip -> xz
, le gzip DEFLATE peut compresser chaque copie des données PNG d'une manière différente, donc xz ne pourra pas détecter les redondances.Le problème est que la plupart des schémas de compression manquent de connaissances sur les données dont vous disposez. Même si vous décompressez vos fichiers PNG en bitmaps et les compressez dans l'archive tar, vous n'obtiendrez pas de résultats (significativement) plus petits.
Dans le cas de nombreuses images similaires, un schéma de compression approprié serait un codec vidéo.
En utilisant un codage sans perte, vous devriez obtenir le résultat de compression presque parfait que vous attendez.
Si vous voulez le tester, utilisez quelque chose comme ceci:
https://trac.ffmpeg.org/wiki/Create%20a%20video%20slideshow%20from%20images
la source
PNG est la combinaison de filtres + LZ77 + Huffman (la combinaison de LZ77 + Huffman est appelée Deflate) dans cet ordre:
étape 1) si le filtre est différent de None, la valeur des pixels est remplacée par la différence avec les pixels adjacents (pour plus de détails, voir http://www.libpng.org/pub/png/book/chapter09.html ) . Cela augmente la compression des images avec des dégradés (donc ... 4 5 6 7 devient ... 1 1 1 1) et cela peut aider dans les zones de la même couleur (... 3 3 3 5 5 5 5 5 devient 0 0 0 2 0 0 0 0 0). Par défaut, les filtres sont activés dans les images 24 bits et désactivés dans les images 8 bits avec une palette.
étape 2) les données sont compressées avec LZ77 qui remplace les chaînes d'octets répétées (correspond) par un tuple contenant la distance jusqu'à la correspondance et la longueur de la correspondance.
étape 3) le résultat de l'étape 2 est codé avec un code Huffman qui remplace les symboles de longueur fixe par des codes de longueur variable, plus le symbole est fréquent, plus le code est court.
Il y a plusieurs problèmes:
Un petit changement qui affecte peu de pixels entraînera des changements dans les résultats des 3 étapes de la compression png:
1) La valeur filtrée des pixels adjacents changera (en fonction du filtre utilisé). Cela amplifiera les effets de petits changements.
2) Le changement signifie que les correspondances avec cette zone seront différentes. Par exemple, si vous changez 333333 en 333533, une autre occurrence de 333333 ne correspondra plus, il sélectionnera donc une autre correspondance avec 333333 avec une distance différente ou sélectionnera la même correspondance mais avec une longueur plus courte, puis une autre correspondance pour les 3 derniers octets. En soi, cela changera beaucoup les résultats.
3) Le problème le plus important est à l'étape 3. Le code huffman utilise un nombre variable de bits, donc même un petit changement entraînera que tout ce qui suit n'est plus aligné. AFAIK La plupart des algorithmes de compression ne peuvent pas détecter les correspondances qui ne sont pas alignées en octets, ce qui empêchera (ou du moins réduira beaucoup) la compression des données déjà compressées qui suit le changement, sauf si le compresseur peut détecter des correspondances non alignées en octets.
Les autres questions sont déjà couvertes par d'autres réponses:
4) Gzip utilise le même algorithme Deflate avec un dictionnaire de 32 Ko, donc si les fichiers png sont plus grands que 32 Ko, les correspondances ne seront pas détectées même si elles sont identiques. Bzip2 est meilleur à cet égard car il utilise un bloc de 900 Ko. XZ utilise LZMA, dont l'IIRC a un dictionnaire de 4 Mo dans le niveau de compression par défaut. 5) Le format Zip n'utilise pas de compression solide, il ne compressera donc pas mieux les fichiers similaires ou identiques.
Peut-être que les compresseurs de la famille PAQ ou PPMD se compresseront mieux, mais si vous devez compresser de nombreux fichiers d'images similaires, vous pouvez envisager 3 approches:
1) Stockez les images non compressées (avec PNG -0 ou dans un format sans compression) et compressez avec un compresseur avec un grand dictionnaire ou une taille de bloc. (LZMA fonctionnera bien)
2) Une autre option serait de conserver les filtres mais de supprimer la compression Deflate des PNGs. Cela peut être fait par exemple avec l' utilitaire ( AdvDef ). Ensuite, vous compressez les fichiers PNG non compressés résultants. Après la décompression, vous pouvez conserver le PNG non compressé ou les compresser à nouveau avec AdvDef (mais cela prendra du temps).
Vous devez tester les deux approches pour voir celle qui se comprime le plus.
3) La dernière option serait de convertir les images png dans une vidéo, de la compresser avec un compresseur vidéo sans perte comme x264 sans perte (en prenant particulièrement soin d'utiliser le bon format de couleur), puis d'extraire les images en images png individuelles. Cela peut être fait avec ffmpeg. Vous devez également conserver le mappage entre le numéro de trame et le nom d'origine.
Ce serait l'approche la plus complexe, mais si les pngs font tous partie d'une animation, elle peut être la plus efficace. Cependant, vous aurez besoin d'un format vidéo qui prend en charge la transparence si vous en avez besoin.
Edit: Il existe également le format MNG s'il n'est pas utilisé souvent.
la source
Lorsque vous avez des jeux de données spéciaux, vous utilisez des algorithmes spéciaux, pas des outils polyvalents.
La réponse est que les compressions sans perte que vous avez choisies ne sont pas faites pour ce que vous faites. Personne ne s'attend à ce que vous compressiez la même image deux fois, et même si vous le faites (par accident) une vérification par rapport à toutes les entrées précédentes rendrait votre algorithme O (n ^ 2) (peut-être un peu mieux, mais l'approche naïve au moins serait n ^ 2).
La plupart de vos programmes de compression que vous avez testés lors de l'exécution en O (n) mettent l'accent sur la vitesse par rapport au taux de compression optimal. Personne ne veut faire fonctionner son ordinateur pendant 5 heures juste pour épargner quelques Mo, surtout ces jours-ci. Pour les entrées plus importantes, tout ce qui dépasse O (n) devient un problème d'exécution.
Un autre problème est le bélier. Vous ne pouvez pas accéder à toutes les parties de votre entrée à un moment donné, lorsque l'entrée devient suffisamment grande. Même en faisant abstraction de cela, la plupart des gens ne veulent pas abandonner tout leur RAM ou CPU juste pour compresser quelque chose.
Si vous avez des modèles dans vos fichiers que vous souhaitez compresser, vous devrez effectuer des opérations manuelles sur eux, écrire votre propre compression ou éventuellement utiliser une compression de type "archive" (nano). Une compression pour un stockage à long terme, trop lente pour un usage quotidien.
Une autre option serait potentiellement une compression vidéo sans perte.
la source
Le format de fichier PNG utilise déjà l'algorithme de compression DEFLATE en interne. Il s'agit du même algorithme que celui utilisé par xz, gzip et zip - juste dans certaines variantes.
tar.gz
et ettar.xz
profiter de la similitude entre les fichiers, ce quizip
n'est pas le cas.Donc, en fait, vous effectuez une compression DEFLATE sur des fichiers compressés DEFLATE - c'est pourquoi les fichiers conservent presque la taille d'origine.
Le
bzip2
programme (également un algorithme connexe) est meilleur lorsqu'il s'agit de fichiers (presque) identiques.la source
bzip2
attrape:tar -cjf archive.tar.bz2 *.png
. Mis à jour dans ma réponse.