54 votes

Comment mettre à l'échelle une BufferedImage

En suivant les javadocs, j'ai tenté de mettre à l'échelle une BufferedImage sans succès voici mon code :

BufferedImage image = MatrixToImageWriter.getBufferedImage(encoded);
Graphics2D grph = image.createGraphics();
grph.scale(2.0, 2.0);
grph.dispose();

Je n'arrive pas à comprendre pourquoi cela ne fonctionne pas, une aide ?

1 votes

0 votes

Au moment où nous écrivons ces lignes, la réponse la plus populaire est la mauvaise réponse. Elle met l'image à l'échelle, mais elle renvoie une image de la même taille, avec les 3/4 de l'image manquants. C'est la réponse donnée par trashgod. C'est proche, mais il y a un petit bug.

0 votes

Merci, @MiguelMunoz. Au fur et à mesure que nous recevons des commentaires, je peux modifier la réponse.

76voto

trashgod Points 136305

AffineTransformOp offre la possibilité supplémentaire de choisir le type d'interpolation.

BufferedImage before = getBufferedImage(encoded);
int w = before.getWidth();
int h = before.getHeight();
BufferedImage after = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
AffineTransform at = new AffineTransform();
at.scale(2.0, 2.0);
AffineTransformOp scaleOp = 
   new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
after = scaleOp.filter(before, after);

Le fragment présenté illustre rééchantillonnage pas culture ; ce lien réponse s'adresse aux numéro ; quelques exemples connexes sont examinés aquí .

2 votes

Est-il vraiment nécessaire d'allouer toute la mémoire pour les éléments suivants after quand vous avez une déclaration comme : after = ... ?

3 votes

@Martijn : Cela dépend de quelle ColorModel vous voulez dans filter() . Il renvoie une référence, donc il n'y a pas de mémoire supplémentaire.

0 votes

Y a-t-il un moyen de faire cela avec une largeur et une hauteur souhaitées au lieu d'un facteur d'échelle ?

39voto

charisis Points 824

Malheureusement, les performances de getScaledInstance() sont très faibles, voire problématiques.

L'autre approche consiste à créer une nouvelle image tamponnée et à dessiner une version à l'échelle de l'original sur la nouvelle image.

BufferedImage resized = new BufferedImage(newWidth, newHeight, original.getType());
Graphics2D g = resized.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
    RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(original, 0, 0, newWidth, newHeight, 0, 0, original.getWidth(),
    original.getHeight(), null);
g.dispose();

newWidth,newHeight indiquent la nouvelle taille de la BufferedImage et doivent être calculés correctement. En cas de mise à l'échelle des facteurs :

int newWidth = new Double(original.getWidth() * widthFactor).intValue();
int newHeight = new Double(original.getHeight() * heightFactor).intValue();

EDIT : J'ai trouvé l'article illustrant le problème de performance : Les périls d'Image.getScaledInstance()

1 votes

Je pense que getScaledInstance() est plus rapide de nos jours, du moins si vous avez une carte graphique décente, grâce au pipeline de rendu Java2D optimisé.

1 votes

Pour info, voir aquí d'autres valeurs possibles pour RenderingHints.KEY_INTERPOLATION

0 votes

Ça a marché comme un charme !

13voto

ceklock Points 1186

Utilisation de imgscalr - Bibliothèque Java de mise à l'échelle des images :

BufferedImage image =
     Scalr.resize(originalImage, Scalr.Method.BALANCED, newWidth, newHeight);

C'est assez rapide pour moi.

1 votes

Je suis d'accord, c'est la meilleure solution et elle évite tous les problèmes de transparence, de mauvaises traductions, de mauvaises couleurs, etc. lors de l'utilisation de l'affinetransform et des diverses autres méthodes.

1 votes

Génial ! La première solution que j'ai vue sur ce fil de discussion qui m'a permis d'obtenir ce dont j'avais besoin.

10voto

aioobe Points 158466

Comme le dit @Bozho, vous voulez probablement utiliser getScaledInstance .

Pour comprendre comment grph.scale(2.0, 2.0) fonctionne cependant, vous pouvez jeter un coup d'œil à ce code :

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

class Main {
    public static void main(String[] args) throws IOException {

        final int SCALE = 2;

        Image img = new ImageIcon("duke.png").getImage();

        BufferedImage bi = new BufferedImage(SCALE * img.getWidth(null),
                                             SCALE * img.getHeight(null),
                                             BufferedImage.TYPE_INT_ARGB);

        Graphics2D grph = (Graphics2D) bi.getGraphics();
        grph.scale(SCALE, SCALE);

        // everything drawn with grph from now on will get scaled.

        grph.drawImage(img, 0, 0, null);
        grph.dispose();

        ImageIO.write(bi, "png", new File("duke_double_size.png"));
    }
}

Étant donné que duke.png :
enter image description here

il produit duke_double_size.png :
enter image description here

1 votes

J'ai essayé ce code, mais je n'ai pas obtenu le résultat indiqué. Le résultat que j'ai obtenu était beaucoup plus fortement aliéné. Si vous zoomez sur la première image dans votre navigateur, jusqu'à obtenir une image de la même taille que la seconde, vous aurez une meilleure idée de ce que produit ce code. (J'ai essayé de mettre l'image résultante dans ce commentaire, mais ça n'a pas marché. Je suppose que les images ne sont pas autorisées dans les commentaires).

0 votes

Pourriez-vous essayer grph.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation); donde interpolation est RenderingHints.VALUE_INTERPOLATION_... par exemple VALUE_INTERPOLATION_BICUBIC ?

3voto

Bozho Points 273663

scale(..) fonctionne un peu différemment. Vous pouvez utiliser bufferedImage.getScaledInstance(..)

0 votes

J'ai essayé de cette façon, mais getScaledInstance renvoie ToolkitImage, et pour mon objectif, cela ne me convient pas. Merci.

2 votes

Vous pouvez le convertir en une BufferedImage en copiant sa trame dans une nouvelle BufferedImage. Recherchez 'convertir une image en image tamponnée'.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X