Réduction du poids des images


Contenu du snippet

De nos jours la plupart des appareils mobiles qui prennent des photos générent des fichiers plus gros qu'ils ne devraient, consommant inutilement de la mémoire alors que celle-ci est souvent limitée.

Le programme que je propose ici va copier tout les fichiers d'un répertoire en réencodant les images de manière à obtenir des fichiers de taille normale et ce sans perdre la qualité de l'image.

Le gain de taille varie d'une image à l'autre, elle peut atteindre jusqu'à 90% pour des images avec peu de détails, même si en moyenne on aura plutôt un gain entre 40 et 50%.

Remarque : il est inutile de traiter une deuxième fois une image déjà réduite, le réencodage supprime uniquement les données superflues, en conséquence puisque celles-ci sont éliminées lors du premier traitement, le deuxième traitement ne pourra rien faire de mieux.

Exemple d'utilisation :

javac ccm\kx\ImageReducer.java
java ccm.kx.ImageReducer "H:\Pictures" "C:\Temp\Pictures"


Code Java 7 :

package ccm.kx;

import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;

import javax.imageio.ImageIO;

public class ImageReducer
{
    /**
     * Extension of images formats that can be supported for ImageIO read and write methods.
     * GIF is not included because transformation will remove animation.
     */
    public static final String[] IMAGE_EXTENSIONS = {"JPG","PNG","BMP"};
    
    /**
     * @param file
     * @return extension of file if any or empty String
     */
    public static String getExtension(File file)
    {
        String name = file.getName();        
        int index = name.lastIndexOf(".");        
        return index==-1 ? "" : name.substring(index+1);
    }
    
    /**
     * @param ext extension of a file
     * @return true if ext is a supported image extension, false otherwise
     */
    public static boolean checkImageExtension(String ext)
    {
        for (String imgExt : IMAGE_EXTENSIONS)
            if (ext.equalsIgnoreCase(imgExt))
                return true;
        
        return false;
    }
    
    /**
     * If input file is an image, output file will be a copy of this image.
     * Input image is transform with a simple read/write operation expecting a size reduction.
     * Output image is the smallest file between original and transform images.
     * 
     * If input file is not an image, output file will be a copy of input.
     * 
     * Last modified time is conserve from input file.
     * 
     * @param input a File to read from
     * @param output a File to be written to
     */
    public static void reduce(File input, File output)
    {
        try
        {
            String ext = getExtension(input);
            
            if (checkImageExtension(ext))
            {
                BufferedImage img = ImageIO.read(input);
                ImageIO.write(img, ext, output);
                
                if (output.length() <= input.length())
                {
                    Files.setLastModifiedTime(output.toPath(), Files.getLastModifiedTime(input.toPath()));
                }
                else
                {
                    Files.copy(input.toPath(), output.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
                }
            }
            else
            {
                Files.copy(input.toPath(), output.toPath(), StandardCopyOption.COPY_ATTRIBUTES);
            }
            
            System.out.printf("%s\t%s\t%d\t%s\t%d\n", ext, input.getAbsolutePath(), input.length(), output.getAbsolutePath(), output.length());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
    
    private static void reduceAll(File srcPath, File dstPath)
    {
        if (!srcPath.exists())
            return;
        
        if (srcPath.isDirectory())
        {
            if (!dstPath.exists())
                dstPath.mkdirs();
            
            for (File src : srcPath.listFiles())
            {
                File dst = new File(dstPath, src.getName());
                reduceAll(src, dst);
            }
        }
        else
        {
            reduce(srcPath, dstPath);
        }
    }

    /**
     * Read fully recursively srcPath, transform each image, and put them in dstPath respecting subfolder hierarchy.
     * @param srcPath a directory to read images from
     * @param dstPath a directory to be written to
     */
    public static void reduceAll(String pathSrc, String pathDst)
    {
        reduceAll(new File(pathSrc), new File(pathDst));
    }
    
    /**
     * @param args {0 : srcPath, 1 : dstPath}
     */
    public static void main(String[] args)
    {
        reduceAll(args[0], args[1]);
    }
}

Compatibilité : 1

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.