Comment redimensionner une image à l'aide de Java?

126

J'ai besoin de redimensionner les fichiers PNG, JPEG et GIF. Comment puis-je faire cela en utilisant Java?

pbreault
la source
14
puisque vous avez demandé une bibliothèque, la vraie réponse est ici: stackoverflow.com/questions/244164/… . C'est beaucoup plus facile à utiliser que le code dans la réponse acceptée;)
Artur Gajowy
Je ne suis pas d'accord sur la partie bibliothèque: Graphics2D fait partie de la bibliothèque awt et est open source. Pour la dernière partie (open source), je ne suis pas sûr à 100%, mais qui regarderait le code awt de toute façon?
Burkhard

Réponses:

87

Après avoir chargé l'image, vous pouvez essayer:

BufferedImage createResizedCopy(Image originalImage, 
            int scaledWidth, int scaledHeight, 
            boolean preserveAlpha)
    {
        System.out.println("resizing...");
        int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
        BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
        Graphics2D g = scaledBI.createGraphics();
        if (preserveAlpha) {
            g.setComposite(AlphaComposite.Src);
        }
        g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null); 
        g.dispose();
        return scaledBI;
    }
Burkhard
la source
9
J'ai trouvé que cette technique crée une image dont la qualité n'est pas suffisante pour mes besoins.
morgancodes
1
Image.getScaledInstance (largeur, hauteur, indices) fera-t-il également l'affaire?
codeplay
1
la vérification de preserveAlpha est-elle dans le mauvais sens (pour l'imageType)?
Thilo
Je suis d'accord avec @morgancodes. La qualité de l'image est bien pire que ce que vous obtenez avec, par exemple, l'aperçu OS X lors du redimensionnement aux mêmes dimensions. J'essaierai quelques bibliothèques open-source pour voir si elles s'en tirent mieux.
Thilo
1
"Je vais essayer des bibliothèques open-source pour voir si elles s'en tirent mieux." +1 pour imgscalr de la réponse de @ RiyadKalla.
Thilo
182

FWIW Je viens de publier (Apache 2, hébergé sur GitHub) une simple bibliothèque de mise à l'échelle d'image pour Java appelée imgscalr (disponible sur Maven central ).

La bibliothèque met en œuvre plusieurs approches différentes de la mise à l'échelle de l'image (y compris l'approche incrémentielle de Chris Campbell avec quelques améliorations mineures) et choisira soit l'approche la plus optimale pour vous si vous le lui demandez, soit vous donnera la plus rapide ou la meilleure apparence (si vous demandez-le).

L'utilisation est extrêmement simple, juste un tas de méthodes statiques. Le cas d'utilisation le plus simple est:

BufferedImage scaledImage = Scalr.resize(myImage, 200);

Toutes les opérations conservent les proportions d'origine de l'image, donc dans ce cas, vous demandez à imgscalr de redimensionner votre image dans des limites de 200 pixels de large et 200 pixels de haut et par défaut, il sélectionnera automatiquement la meilleure approche et la plus rapide pour cela depuis 't spécifié.

Je me rends compte dès le départ que cela ressemble à de l'auto-promotion (c'est le cas), mais j'ai passé ma juste part de temps à googler exactement le même sujet et j'ai continué à proposer des résultats / approches / pensées / suggestions différents et j'ai décidé de m'asseoir et d'écrire un implémentation simple qui répondrait à 80 à 85% des cas d'utilisation où vous avez une image et que vous voulez probablement une vignette pour celle-ci - soit aussi vite que possible ou aussi belle que possible (pour ceux qui ont essayé, vous remarquerez faire un Graphics.drawImage même avec une interpolation BICUBIC vers une image suffisamment petite, cela ressemble toujours à une poubelle).

Riyad Kalla
la source
1
Riyad, j'ai aimé utiliser Scalr. Je suis curieux de savoir, comment avez-vous fini par choisir une API avec toutes les méthodes statiques? J'avais écrit une API similaire qui était plus proche d'un constructeur. Comme new ImageScaler(img).resizeTo(...).rotate(...).cropTo(...).toOutputBuffer(). J'aime aussi ton chemin et je pense que c'est plus simple.
Amir Raminfar
4
Amir, le modèle de constructeur fonctionne à merveille pour ces types de bibliothèques également, il m'est arrivé de suivre l'approche de la méthode statique parce que je pensais que c'était un poil plus facile à suivre pour les nouveaux utilisateurs et le modèle d'utilisation que j'attendais d'imgscalr (à l'origine seules les méthodes de redimensionnement uniques) n'ont pas bénéficié d'un état de maintien d'instance (l'instance du générateur). J'ai donc économisé sur l'instanciation de l'objet et suis allé avec les méthodes statiques. J'ai pris une position ferme contre la création d'objets à l'intérieur d'imgscalr dans tous les endroits où je peux l'éviter. Les deux approches fonctionnent très bien cependant.
Riyad Kalla
5
+1 pour avoir rendu cela disponible sur le référentiel central Maven!
Grilse
Quelle est cette classe BufferedImage, pourquoi Android Studio ne la trouve pas? @Riyad Kalla
Milad
3
@ xe4me BufferedImage est une classe du J2SE JDK (faisant partie du framework Java2D) utilisée pour représenter des données de pixels brutes et non compressées. Il n'est pas disponible sur Android, Android fournit ses propres classes pour travailler avec des données d'image.
Riyad Kalla
54

Thumbnailator est une bibliothèque de redimensionnement d'images open-source pour Java avec une interface fluide, distribuée sous la licence MIT.

J'ai écrit cette bibliothèque parce que créer des vignettes de haute qualité en Java peut être étonnamment difficile, et le code qui en résulte peut être assez compliqué. Avec Thumbnailator, il est possible d'exprimer des tâches assez compliquées en utilisant une API simple et fluide.

Un exemple simple

Pour un exemple simple, prendre une image et la redimensionner à 100 x 100 (en préservant le rapport hauteur / largeur de l'image d'origine) et l'enregistrer dans un fichier peut être réalisée en une seule instruction:

Thumbnails.of("path/to/image")
    .size(100, 100)
    .toFile("path/to/thumbnail");

Un exemple avancé

L'exécution de tâches de redimensionnement complexes est simplifiée grâce à l'interface fluide de Thumbnailator.

Supposons que nous voulions faire ce qui suit:

  1. prendre les images dans un répertoire et,
  2. les redimensionner à 100 x 100, avec le rapport hauteur / largeur de l'image d'origine,
  3. enregistrez-les tous au format JPEG avec des paramètres de qualité de 0.85,
  4. où les noms de fichiers sont tirés de l'original avec thumbnail.ajoutés au début

Traduit en Thumbnailator, nous pourrions effectuer les opérations ci-dessus avec les éléments suivants:

Thumbnails.of(new File("path/to/directory").listFiles())
    .size(100, 100)
    .outputFormat("JPEG")
    .outputQuality(0.85)
    .toFiles(Rename.PREFIX_DOT_THUMBNAIL);

Une note sur la qualité et la vitesse d'image

Cette bibliothèque utilise également la méthode de mise à l' échelle bilinéaire progressive mise en évidence dans Filthy Rich Clients de Chet Haase et Romain Guy afin de générer des vignettes de haute qualité tout en garantissant des performances d'exécution acceptables.

coobird
la source
1
coobird, très bon travail avec l'API. Très simple et facile à utiliser.
Riyad Kalla
@LordT: Je suis heureux que vous ayez trouvé Thumbnailator facile à utiliser :)
coobird
Comment créer une miniature 80x80 avec une image originale 500x400? je n'ai vu aucune option pour cela. Merci!
terry
".outputFormat (" JPEG ")" n'est écrit nulle part dans la documentation.
Vincent Cantin
@Vincent La liste complète des méthodes qui peuvent être utilisées se trouve dans la documentation de l'API Thumbnailator - thumbnailator.googlecode.com/hg/javadoc/net/coobird/…
coobird
12

Vous n'avez pas besoin d'une bibliothèque pour cela. Vous pouvez le faire avec Java lui-même.

Chris Campbell a un excellent article détaillé sur la mise à l'échelle des images - voir cet article .

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

David Koelle
la source
7
L'article de Chris est exactement ce qui m'a motivé à écrire imgscalr en premier lieu; et des questions comme celle-ci (et des réponses comme la vôtre). Beaucoup de gens demandent encore et encore comment obtenir de belles vignettes à partir d'une image. Il y a plusieurs façons de le faire, Chris n'est pas toujours la meilleure façon, cela dépend de ce que vous essayez de faire et de l'ampleur de la réduction. imgscalr répond à tout cela et c'est une classe.
Riyad Kalla
2
+1, je suis d'accord, Filthy Rich clients est l'un des meilleurs livres java à égalité avec "Effective java", mais ImgScalr est ce que j'utilise parce que je suis paresseux.
Shawn Vader
9

Si vous avez affaire à de grandes images ou que vous voulez un joli résultat, ce n'est pas une tâche triviale en java. Le faire simplement via une opération de redimensionnement via Graphics2D ne créera pas une vignette de haute qualité. Vous pouvez le faire en utilisant JAI, mais cela nécessite plus de travail que vous ne l'imaginez pour obtenir quelque chose qui semble bon et JAI a la mauvaise habitude de faire exploser votre JVM avec des erreurs OutOfMemory.

Je suggère d'utiliser ImageMagick comme exécutable externe si vous pouvez vous en tirer. C'est simple à utiliser et il fait le travail correctement pour que vous n'ayez pas à le faire.

Joël Carranza
la source
4

Si, avoir imagemagick installé sur votre machine est une option, je recommande im4java . C'est une couche d'abstraction très fine sur l'interface de ligne de commande, mais fait très bien son travail.

naltatis
la source
3

L'API Java ne fournit pas de fonction de mise à l'échelle standard pour les images et de rétrogradation de la qualité d'image.

Pour cette raison, j'ai essayé d'utiliser cvResize de JavaCV mais cela semble poser des problèmes.

J'ai trouvé une bonne bibliothèque pour la mise à l'échelle d'image: ajoutez simplement la dépendance pour "java-image-scaling" dans votre pom.xml.

<dependency>
    <groupId>com.mortennobel</groupId>
    <artifactId>java-image-scaling</artifactId>
    <version>0.8.6</version>
</dependency>

Dans le référentiel maven, vous obtiendrez la version récente pour cela.

Ex. Dans votre programme java

ResampleOp resamOp = new ResampleOp(50, 40);
BufferedImage modifiedImage = resamOp.filter(originalBufferedImage, null);
Ruju
la source
Il est également disponible sur GitHub ( github.com/mortennobel/java-image-scaling.git ) et il a la version 8.7 pour l'instant. Il avait besoin d'un correctif li'l dans pom.xml, toi (changer la source et la cible à au moins 1.6 car le plus récent Maven ne supporte plus la 1.5).
Cromax
2

Vous pouvez essayer d'utiliser le système de traitement d'images GraphicsMagick avec im4java comme interface de ligne de commande pour Java.

GraphicsMagick présente de nombreux avantages, mais un pour tous:

  • GM est utilisé pour traiter des milliards de fichiers sur les plus grands sites de photos du monde (par exemple Flickr et Etsy).
kajo
la source
1

Image Magick a été mentionnée. Il existe un projet frontal JNI appelé JMagick. Ce n'est pas un projet particulièrement stable (et Image Magick lui-même est connu pour changer beaucoup et même casser la compatibilité). Cela dit, nous avons une bonne expérience de l'utilisation de JMagick et d'une version compatible d'Image Magick dans un environnement de production pour effectuer une mise à l'échelle à un débit élevé et à un faible taux de latence. La vitesse était nettement meilleure qu'avec une bibliothèque graphique entièrement Java que nous avions précédemment essayée.

http://www.jmagick.org/index.html

Jice
la source
1

Utilisez simplement la réponse de Burkhard mais ajoutez cette ligne après avoir créé les graphiques:

    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

Vous pouvez également définir la valeur sur BICUBIC, cela produira une image de meilleure qualité mais c'est une opération plus coûteuse. Il existe d'autres conseils de rendu que vous pouvez définir, mais j'ai trouvé que l'interpolation produit l'effet le plus notable. Gardez à l'esprit que si vous souhaitez zoomer beaucoup, le code java sera très probablement très lent. Je trouve que les images plus grandes commencent à produire un décalage d'environ 300% de zoom, même avec tous les conseils de rendu définis pour optimiser la vitesse par rapport à la qualité.

Le seul vrai Colter
la source
1

Il s'avère que l'écriture d'un scaler performant n'est pas anodine. Je l'ai fait une fois pour un projet open source: ImageScaler .

En principe, 'java.awt.Image # getScaledInstance (int, int, int)' ferait également l'affaire, mais il y a un bogue désagréable avec cela - reportez-vous à mon lien pour plus de détails.

aanno
la source
0

J'ai développé une solution avec les classes disponibles gratuitement (AnimatedGifEncoder, GifDecoder et LWZEncoder) disponibles pour gérer les animations GIF.
Vous pouvez télécharger le fichier jgifcode et exécuter la classe GifImageUtil. Lien: http://www.jgifcode.com

Rohit Tiwari
la source
1
Veuillez mentionner dans la réponse si vous êtes affilié au produit que vous recommandez.
Hans Olsson
waw ... est-ce pour redimensionner l'image animée GIF? et c'est gratuit ?? Wwaww ... je devrais l'essayer maintenant ...
gumuruh
Oui, cela est développé par moi. Voici le code source pour cela github.com/rt29/jgifcode - Ceci est maintenant ici. Je ne le soutiens plus.
Rohit Tiwari
0

Si vous ne voulez pas importer imgScalr comme la réponse @Riyad Kalla ci-dessus que j'ai testée fonctionne aussi bien, vous pouvez le faire à partir de la réponse de Peter Walser @Peter Walser sur un autre problème:

 /**
     * utility method to get an icon from the resources of this class
     * @param name the name of the icon
     * @return the icon, or null if the icon wasn't found.
     */
    public Icon getIcon(String name) {
        Icon icon = null;
        URL url = null;
        ImageIcon imgicon = null;
        BufferedImage scaledImage = null;
        try {
            url = getClass().getResource(name);

            icon = new ImageIcon(url);
            if (icon == null) {
                System.out.println("Couldn't find " + url);
            }

            BufferedImage bi = new BufferedImage(
                    icon.getIconWidth(),
                    icon.getIconHeight(),
                    BufferedImage.TYPE_INT_RGB);
            Graphics g = bi.createGraphics();
            // paint the Icon to the BufferedImage.
            icon.paintIcon(null, g, 0,0);
            g.dispose();

            bi = resizeImage(bi,30,30);
            scaledImage = bi;// or replace with this line Scalr.resize(bi, 30,30);
            imgicon = new ImageIcon(scaledImage);

        } catch (Exception e) {
            System.out.println("Couldn't find " + getClass().getName() + "/" + name);
            e.printStackTrace();
        }
        return imgicon;
    }

 public static BufferedImage resizeImage (BufferedImage image, int areaWidth, int areaHeight) {
        float scaleX = (float) areaWidth / image.getWidth();
        float scaleY = (float) areaHeight / image.getHeight();
        float scale = Math.min(scaleX, scaleY);
        int w = Math.round(image.getWidth() * scale);
        int h = Math.round(image.getHeight() * scale);

        int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;

        boolean scaleDown = scale < 1;

        if (scaleDown) {
            // multi-pass bilinear div 2
            int currentW = image.getWidth();
            int currentH = image.getHeight();
            BufferedImage resized = image;
            while (currentW > w || currentH > h) {
                currentW = Math.max(w, currentW / 2);
                currentH = Math.max(h, currentH / 2);

                BufferedImage temp = new BufferedImage(currentW, currentH, type);
                Graphics2D g2 = temp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2.drawImage(resized, 0, 0, currentW, currentH, null);
                g2.dispose();
                resized = temp;
            }
            return resized;
        } else {
            Object hint = scale > 2 ? RenderingHints.VALUE_INTERPOLATION_BICUBIC : RenderingHints.VALUE_INTERPOLATION_BILINEAR;

            BufferedImage resized = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2 = resized.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            g2.drawImage(image, 0, 0, w, h, null);
            g2.dispose();
            return resized;
        }
    }
shareef
la source
0

Essayez cette méthode suivante:

ImageIcon icon = new ImageIcon("image.png");
Image img = icon.getImage();
Image newImg = img.getScaledInstance(350, 350, java.evt.Image.SCALE_SMOOTH);
icon = new ImageIcon(img);
JOptionPane.showMessageDialog(null, "image on The frame", "Display Image", JOptionPane.INFORMATION_MESSAGE, icon);
Fridjato Partie Fridjat
la source