Accueil > Development, Python > Compresser un Jpeg à une taille donnée… en préservant les métadonnées

Compresser un Jpeg à une taille donnée… en préservant les métadonnées

Tout d’abord merci à Zigazou d’avoir partagé le script original et pour le temps qu’il m’a fait gagné !

De mon côté, si l’algorithme est exactement celui qu’il me fallait, je devais toutefois conserver les métadonnées des images. La conversion en PNM les supprimant toutes, j’ai tout d’abord pensé les sauvegarder puis les restaurer à l’aide de l’indispensable exiftool.

Malheureusement, je ne suis pas parvenu à réinjecter l’intégralité des champs (impossible notamment de réécrire la famille ICC_Profile malgré que celle-ci soit théoriquement supportée).

Après des heures de bagarre infructueuse, je décide de chercher une autre stratégies et pense soudain que, plus tôt dans mon workflow, convert (du paquet imagemagick) me convertit parfaitement les TIFF en JPEG en transférant impeccablement les métadonnées !

Je m’attaque donc à la page de man de convert (prévoyez un p’tit café !) et finit par tomber sur l’option espérée: -quality permettant de régler le niveau de compression des fichiers JPEG/MIFF/PNG. Un rapide test de recompression… Joie, tous les champs sont là !

Je vous livre donc ma version adaptée du script Python de Zigazou:

#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
"""Reduce JPEG file to the desired weight

Original script by zigazou:
http://zigazou.wordpress.com/2009/05/07/compresser-un-jpeg-a-une-taille-donnee/

The script uses convert utility from imagemagick package.
On Debian and derivatives, install it with:
        apt-get install imagemagick

Usage:
        jpegoptim   [ ...]

This version preserves metadatas which may lead to higher compression
to reach the target file weight, and so, lower quality.

Input files are overwritten

"""

import sys
from subprocess import Popen, PIPE

# Compress JPEG file to given quality with no color downsampling
def shell_command(quality,filename):
    p = Popen(["convert", "-quality", str(quality),
        "-sampling-factor", "4:4:4", filename, '-'],
        stdout=PIPE)

    return p.communicate()[0]

# "Compute" file weight for the given quality
# File (re)compression is actually done, even if discarded, so this
# can be very resource intensive
# TODO: maybe add process "renicing"
def compute(quality, filename):
        return len(shell_command(quality, filename))

# Finally generate the optimized file
def generate(quality, filename_in, filename_out):
        output = shell_command(quality, filename_in)

        f = open(filename_out, "w")
        f.write(output)
        f.close()

# Generic, dichotomic search function
def find_param(minimum, maximum, search_result, function, func_parms):
        index = (minimum + maximum) / 2
        best_index = index
        best_result = function(best_index, func_parms)
        result = best_result

        while index not in (minimum, maximum) and best_result != search_result:
                result = function(index, func_parms)

                if result  abs(search_result - result):
                        best_result = result
                        best_index = index

                index = (minimum + maximum) / 2

        if abs(search_result - best_result) > abs(search_result - result):
                best_result = result
                best_index = index

        return best_index

for fName in sys.argv[2:]:
    quality = find_param(0, 100, int(sys.argv[1]) * 1024, compute, fName)
    generate(quality, fName)

# vim: ts=4:sts=4:sw=4:et:ft=python:

Dans mon cas, j’ai préféré ne pas jouer sur l’échantillonnage des couleurs. Ceci est toutefois possible grâce au paramètre -sampling-factor en lui donnant les valeurs 4:2:2 pour un sous-échantillonnage standard, ou encore 4:1:1 pour une réduction maximum (pire qualité).

Pour plus d’informations sur cette question, je vous recommande la lecture de la page suivante: Optimization of JPEG (JPG) images: good quality and small size.

Encore merci à Zigazou qui m’a sauvé quelques poils sur le cailloux😉

  1. Aucun commentaire pour l’instant.
  1. No trackbacks yet.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :