java - without - spring image resize




Java 2D et redimensionner (4)

Chris Campbell a un excellent et détaillé article sur les images à l'échelle - voir cet article .

Chet Haase et Romain Guy ont également une description détaillée et très informative de la mise à l'échelle des images dans leur livre, Filthy Rich Clients .

J'ai un vieux code 2D Java que je veux réutiliser, mais je me demandais, est-ce la meilleure façon d'obtenir des images de la plus haute qualité?

    public static BufferedImage getScaled(BufferedImage imgSrc, Dimension dim) {

    //  This code ensures that all the pixels in the image are loaded.
    Image scaled = imgSrc.getScaledInstance(
            dim.width, dim.height, Image.SCALE_SMOOTH);

    // This code ensures that all the pixels in the image are loaded.
    Image temp = new ImageIcon(scaled).getImage();

    // Create the buffered image.
    BufferedImage bufferedImage = new BufferedImage(temp.getWidth(null), 
            temp.getHeight(null), BufferedImage.TYPE_INT_RGB);

    // Copy image to buffered image.
    Graphics g = bufferedImage.createGraphics();
    // Clear background and paint the image.
    g.setColor(Color.white);
    g.fillRect(0, 0, temp.getWidth(null),temp.getHeight(null));
    g.drawImage(temp, 0, 0, null);
    g.dispose();


    // j2d's image scaling quality is rather poor, especially when
    // scaling down an image to a much smaller size. We'll post filter  
    // our images using a trick found at 
    // http://blogs.cocoondev.org/mpo/archives/003584.html
    // to increase the perceived quality....
    float origArea = imgSrc.getWidth() * imgSrc.getHeight();
    float newArea = dim.width * dim.height;
    if (newArea <= (origArea / 2.)) {
        bufferedImage = blurImg(bufferedImage);
    }

    return bufferedImage;
}

public static BufferedImage blurImg(BufferedImage src) {
    // soften factor - increase to increase blur strength
    float softenFactor = 0.010f;
    // convolution kernel (blur)
    float[] softenArray = {
            0,              softenFactor,       0, 
            softenFactor, 1-(softenFactor*4), softenFactor, 
            0,              softenFactor,       0};

    Kernel kernel = new Kernel(3, 3, softenArray);
    ConvolveOp cOp = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
    return cOp.filter(src, null);
}

Vous pouvez utiliser JAI (Java Advanced Imaging) pour obtenir des options de redimensionnement d'image plus sophistiquées. Voir https://jai.dev.java.net/ . Ceux-ci vous permettent beaucoup plus de flexibilité que le paquetage java.awt.image.


Ajout de quelques informations de clarification ici.

Non, ce n'est pas la meilleure façon d'obtenir une belle image à l'échelle en Java. L'utilisation de getScaledInstance et du AreaAveragingScaleFilter sous-jacent est déconseillée par l'équipe Java2D en faveur de certaines méthodes plus avancées.

Si vous essayez juste d'obtenir une belle miniature, l'utilisation de la méthode de Chris Campbell comme suggéré par David est la voie à suivre. Pour ce que ça vaut, j'ai implémenté cet algorithme avec 2 autres méthodes plus rapides dans une bibliothèque de mise à l'échelle Java appelée imgscalr (licence Apache 2). Le but de la bibliothèque était d'adresser spécifiquement cette question dans une bibliothèque fortement réglée qui est facile à utiliser:

BufferedImage thumbnail = Scalr.resize(srcImg, 150);

Pour obtenir l'instance mise à l'échelle la plus belle possible en Java, l'appel de méthode ressemblerait à ceci:

BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 
                                       150, 100, Scalr.OP_ANTIALIAS);

La bibliothèque mettra à l'échelle l'image originale en utilisant l'approche incrémentielle-mise à l'échelle recommandée par l'équipe Java2D et ensuite, pour faire paraître encore plus agréable, une convolveop très légère est appliquée à l'image, l'anti-aliasing efficacement. C'est vraiment sympa pour les petites vignettes, pas si important pour les grandes images.

Si vous n'avez pas travaillé avec des convolveops auparavant, c'est BEAUCOUP de travail juste pour obtenir le noyau parfait pour que l'opération soit belle dans tous les cas d'utilisation. La constante OP définie sur la classe Scalr est le résultat d'une semaine de collaboration avec un site de réseau social au Brésil qui avait déployé imgscalr pour traiter les images de profil pour ses membres. Nous sommes allés dans les deux sens et avons essayé quelque chose comme 10 noyaux différents jusqu'à ce que nous en trouvions un qui était assez subtil pour ne pas rendre l'image plus douce ou floue mais lisser les transitions entre les valeurs de pixels. à petites tailles.

Si vous voulez la meilleure image mise à l' échelle sans tenir compte de la vitesse, allez avec la suggestion de Juha d'utiliser la bibliothèque java-image-scaling. C'est une collection très complète de Java2D Ops et inclut le support de l' algorithme de Lanczsos qui vous donnera le meilleur résultat.

Je voudrais rester loin de JAI, pas parce que c'est mauvais, mais parce que c'est juste un outil différent / plus large que ce que vous essayez de résoudre. L'une des 3 approches mentionnées précédemment vous donnera de superbes miniatures sans avoir besoin d'ajouter une nouvelle plate-forme d'imagerie à votre projet en moins de lignes de code.


Vous pouvez redimensionner l'image en utilisant une bibliothèque Open Source .

J'ai fait avec Large Image to Small et résultat excellent, gardant le rapport d'aspect bien.

import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import org.imgscalr.*;
import org.imgscalr.Scalr.Method;


public class ImageScaller {
static String SRC_FILES_PATH = "I:\\BigGreen\\";
static String IMAGE_FILE_PATH = "I:\\Resized\\";
public ImageScaller() {         
}   
public static void main(String[] args) {
    // TODO Auto-generated method stub
    try
    {
        ResizeLoad(SRC_FILES_PATH);
    }
    catch(Exception ex)
    {
        System.out.println(ex.toString());
    }
}
public static int ResizeLoad(String path)
{
    String file;
    File folder ;
    File[] listOfFiles = null;       
    listOfFiles = null;
    try
    {           
        folder = new File(path);
        listOfFiles = folder.listFiles();   

        for (int i = 0; i < listOfFiles.length; i++)                    
        {                   
            if (listOfFiles[i].isFile())
            {
                file = listOfFiles[i].getName();
                ScalledImageWrite(listOfFiles[i].getPath(),file);                                   
                //System.out.println(file);
                }
            }
        System.out.println("All Resized");
        }

    catch (Exception e) 
      {
          JOptionPane.showMessageDialog(null,e.toString(),"Resize & Load :Exception",JOptionPane.WARNING_MESSAGE);                
      }
    return listOfFiles.length;
}
private static File ScalledImageWrite(String path,String fileName) 
  {
      try
      {
          BufferedImage img = ImageIO.read(new File(path));            
          BufferedImage scaledImg = Scalr.resize(img, Method.AUTOMATIC, 24, 24);                 
          File destFile = new File(IMAGE_FILE_PATH + fileName);      
          ImageIO.write(scaledImg, "png", destFile);                  
          //System.out.println("Done resizing");
          return destFile;
      }
      catch (Exception e) 
      {
          JOptionPane.showMessageDialog(null,e.toString(),"Scalled Images Write: Exception",JOptionPane.WARNING_MESSAGE);
          return null;
      }
  }

}

Voici la sortie en format pictural de ce code.





image-scaling