Como redimensionar uma imagem usando Java?

126

Preciso redimensionar arquivos PNG, JPEG e GIF. Como posso fazer isso usando Java?

pbreault
fonte
14
desde que você solicitou uma biblioteca, a resposta real está aqui: stackoverflow.com/questions/244164/… . É muito mais fácil de usar do que o código em resposta aceita;)
Artur Gajowy
Discordo da parte da biblioteca: O Graphics2D faz parte da biblioteca awt e é de código aberto. Para a última parte (código aberto), não tenho 100% de certeza, mas quem veria o código awt de qualquer maneira?
precisa

Respostas:

87

Depois de carregar a imagem, você pode tentar:

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
fonte
9
Eu descobri que essa técnica cria uma imagem que não é de qualidade suficiente para minhas necessidades.
morgancodes
1
Image.getScaledInstance (largura, altura, dicas) também funciona?
codeplay
1
o preserveAlpha verifica o caminho errado (para o imageType)?
Thilo
Eu concordo com @morgancodes. A qualidade da imagem é muito pior do que a que você obtém, por exemplo, OS X Preview ao redimensionar para as mesmas dimensões. Tentará algumas bibliotecas de código aberto para ver se elas se saem melhor.
Thilo
1
"Vou tentar algumas bibliotecas de código aberto para ver se elas se saem melhor." +1 para imgscalr da resposta de @ RiyadKalla.
Thilo
182

FWIW Acabei de lançar (Apache 2, hospedado no GitHub) uma biblioteca simples de dimensionamento de imagens para Java chamada imgscalr (disponível no Maven central ).

A biblioteca implementa algumas abordagens diferentes para o dimensionamento de imagens (incluindo a abordagem incremental de Chris Campbell com alguns aprimoramentos menores) e escolherá a melhor abordagem para você, se você pedir, ou fornecerá a aparência mais rápida ou bonita (se você peça isso).

O uso é simples, apenas um monte de métodos estáticos. O caso de uso mais simples é:

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

Todas as operações mantêm as proporções originais da imagem; portanto, neste caso, você está solicitando ao imgscalr que redimensione sua imagem dentro de limites de 200 pixels de largura e 200 pixels de altura e, por padrão, selecionará automaticamente a abordagem mais rápida e bonita para isso, pois não foi possível. não especificado.

Percebo desde o início que isso se parece com autopromoção (é), mas gastei minha parte justa do tempo pesquisando exatamente esse mesmo assunto e continuei apresentando diferentes resultados / abordagens / pensamentos / sugestões e decidi sentar e escrever uma implementação simples que abordaria os casos de uso de 80 a 85% em que você tem uma imagem e provavelmente deseja uma miniatura para ela - o mais rápido possível ou o mais bonito possível (para aqueles que tentaram, você notará fazendo uma Graphics.drawImage, mesmo com interpolação BICUBIC em uma imagem pequena o suficiente, ainda parece lixo).

Riyad Kalla
fonte
1
Riyad, gostei de usar o Scalr. Estou curioso para saber, como você acabou escolhendo uma API com todos os métodos estáticos? Eu havia escrito uma API semelhante, mais próxima de um construtor. Like new ImageScaler(img).resizeTo(...).rotate(...).cropTo(...).toOutputBuffer(). Também gosto do seu jeito e acho que é mais simples.
Amir Raminfar
4
Amir, o padrão do construtor também funciona maravilhosamente para esses tipos de bibliotecas, por acaso eu segui a abordagem do método estático, porque achei que era um cabelo mais fácil de seguir para novos usuários e o padrão de uso que eu esperava do imgscalr (originalmente apenas métodos de redimensionamento único) não se beneficiaram de ter uma instância mantendo o estado (A instância do construtor). Então eu salvei na instanciação do objeto e fui com os métodos estáticos. Adotei uma forte posição contra a criação de objetos dentro do imgscalr em todos os lugares em que posso evitá-lo. Ambas as abordagens funcionam muito bem.
Riyad Kalla
5
+1 por disponibilizá-lo no repositório central do Maven!
Grilse 21/09/12
O que é essa classe BufferedImage, por que o estúdio android não a encontra? @Riyad Kalla
Milad
3
@ xe4me BufferedImage é uma classe no J2SE JDK (parte da estrutura Java2D) usada para representar dados de pixel brutos e não compactados. Ele não está disponível no Android, o Android fornece suas próprias classes para trabalhar com dados de imagem.
Riyad Kalla 23/03
54

Thumbnailator é uma biblioteca de redimensionamento de imagem de código aberto para Java com uma interface fluente, distribuída sob a licença MIT.

Eu escrevi esta biblioteca porque criar miniaturas de alta qualidade em Java pode ser surpreendentemente difícil e o código resultante pode ser bastante confuso. Com o Thumbnailator, é possível expressar tarefas bastante complicadas usando uma API fluente simples.

Um exemplo simples

Para um exemplo simples, é possível obter uma imagem e redimensioná-la para 100 x 100 (preservando a proporção da imagem original) e salvando-a em um arquivo em uma única declaração:

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

Um exemplo avançado

A execução de tarefas complexas de redimensionamento é simplificada com a interface fluente do Thumbnailator.

Vamos supor que queremos fazer o seguinte:

  1. pegue as imagens em um diretório e,
  2. redimensione-os para 100 x 100, com a proporção da imagem original,
  3. salve todos eles em JPEGs com configurações de qualidade de 0.85,
  4. onde os nomes dos arquivos são retirados do original e thumbnail.anexados ao início

Traduzido para o Thumbnailator, poderíamos executar o acima com o seguinte:

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

Uma observação sobre a qualidade e velocidade da imagem

Essa biblioteca também usa o método de dimensionamento bilinear progressivo destacado em Filthy Rich Clients por Chet Haase e Romain Guy, a fim de gerar miniaturas de alta qualidade e garantir um desempenho de tempo de execução aceitável.

coobird
fonte
1
coobird, trabalho muito bom com a API. Muito simples e fácil de usar.
Riyad Kalla
@LordT: Estou feliz que você encontrou Thumbnailator para ser fácil de usar :)
coobird
Como posso criar uma miniatura de 80 x 80 com uma imagem original de 500 x 400? eu não vi nenhuma opção para isso. obrigado!
terry
".outputFormat (" JPEG ")" não está escrito em nenhum lugar da documentação.
Vincent Cantin
@Vincent A lista completa de métodos que podem ser utilizados está na documentação API Thumbnailator - thumbnailator.googlecode.com/hg/javadoc/net/coobird/...
coobird
12

Você não precisa de uma biblioteca para fazer isso. Você pode fazer isso com o próprio Java.

Chris Campbell tem um excelente e detalhado artigo sobre dimensionamento de imagens - consulte este artigo .

Chet Haase e Romain Guy também têm uma descrição detalhada e muito informativa do dimensionamento de imagens em seu livro Filthy Rich Clients .

David Koelle
fonte
7
O artigo de Chris é exatamente o que me motivou a escrever imgscalr em primeiro lugar; e perguntas como essa (e respostas como a sua). Muitas pessoas perguntam repetidamente como obter miniaturas com boa aparência de uma imagem. Existem várias maneiras de fazer isso, o Chris nem sempre é o melhor, depende do que você está tentando fazer e do tamanho da redução. O imgscalr aborda tudo isso e é uma classe.
Riyad Kalla
2
+1, eu concordo, o Filthy Rich clients é um dos melhores livros em Java, a par do "Effective java", mas o ImgScalr é o que eu uso porque sou preguiçoso.
Shawn Vader #
9

Se você está lidando com imagens grandes ou deseja um resultado bonito, não é uma tarefa trivial em java. Simplesmente fazê-lo através de uma operação de revenda via Graphics2D não criará uma miniatura de alta qualidade. Você pode fazer isso usando JAI, mas requer mais trabalho do que você imagina para obter algo que pareça bom e a JAI tem o hábito desagradável de explodir nossa JVM com erros OutOfMemory.

Eu sugiro usar o ImageMagick como um executável externo, se você puder se safar. É simples de usar e faz o trabalho corretamente para que você não precise.

Joel Carranza
fonte
4

Se a opção imagemagick instalada no seu maschine for uma opção, eu recomendo o im4java . É uma camada de abstração muito fina na interface da linha de comando, mas faz seu trabalho muito bem.

naltatis
fonte
3

A API Java não fornece um recurso de escala padrão para imagens e redução da qualidade da imagem.

Por causa disso, tentei usar o cvResize do JavaCV, mas parece causar problemas.

Encontrei uma boa biblioteca para dimensionamento de imagens: basta adicionar a dependência para "java-image-scaling" no seu pom.xml.

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

No repositório maven, você obterá a versão recente para isso.

Ex. No seu programa java

ResampleOp resamOp = new ResampleOp(50, 40);
BufferedImage modifiedImage = resamOp.filter(originalBufferedImage, null);
Ruju
fonte
Ele também está disponível no GitHub ( github.com/mortennobel/java-image-scaling.git ) e possui a versão 8.7 até o momento. Ele precisava ser corrigido no pom.xml, tu (alterando a origem e o destino para pelo menos 1,6, pois o Maven mais recente não suporta mais o 1.5).
precisa saber é o seguinte
2

Você pode tentar usar o GraphicsMagick Image Processing System com o im4java como uma interface de linha de para Java.

Existem muitas vantagens do GraphicsMagick, mas uma por todas:

  • O GM é usado para processar bilhões de arquivos nos maiores sites de fotos do mundo (por exemplo, Flickr e Etsy).
kajo
fonte
1

Image Magick foi mencionado. Existe um projeto de front end da JNI chamado JMagick. Não é um projeto particularmente estável (e se sabe que o Image Magick muda muito e até quebra a compatibilidade). Dito isso, tivemos uma boa experiência usando o JMagick e uma versão compatível do Image Magick em um ambiente de produção para executar o dimensionamento com alta taxa de transferência e baixa latência. A velocidade foi substancialmente melhor do que com uma biblioteca de gráficos Java que tentamos anteriormente.

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

Jice
fonte
1

Basta usar a resposta de Burkhard, mas adicione esta linha depois de criar os gráficos:

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

Você também pode definir o valor como BICUBIC, ele produzirá uma imagem de melhor qualidade, mas é uma operação mais cara. Existem outras dicas de renderização que você pode definir, mas eu descobri que a interpolação produz o efeito mais notável. Lembre-se de que, se você quiser aumentar bastante o zoom, o código java provavelmente será muito lento. Acho que imagens maiores começam a produzir lag em torno de 300% de zoom, mesmo com todas as dicas de renderização definidas para otimizar a velocidade sobre a qualidade.

O único verdadeiro colter
fonte
1

Acontece que escrever um scaler de desempenho não é trivial. Eu fiz isso uma vez para um projeto de código aberto: ImageScaler .

Em princípio, 'java.awt.Image # getScaledInstance (int, int, int)' também faria o trabalho, mas há um bug desagradável com isso - consulte meu link para obter detalhes.

aanno
fonte
0

Eu desenvolvi uma solução com as classes disponíveis gratuitamente (AnimatedGifEncoder, GifDecoder e LWZEncoder) disponíveis para lidar com animação GIF.
Você pode fazer o download do jar jgifcode e executar a classe GifImageUtil. Link: http://www.jgifcode.com

Rohit Tiwari
fonte
1
Mencione na resposta se você é afiliado ao produto recomendado.
Hans Olsson
waw ... é isso para redimensionar a imagem animada GIF? e é grátis ?? Wwaww ... i deve experimentá-lo agora ...
gumuruh
Sim, isso é desenvolvido por mim. Aqui está o código fonte github.com/rt29/jgifcode - Agora está aqui. Não estou mais apoiando isso.
Rohit Tiwari
0

Se você não deseja importar o imgScalr como a resposta de @Riyad Kalla acima da qual eu testei também funciona bem, você pode fazer isso com Peter Walser, responda a @ Peter Walser em outra questão:

 /**
     * 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
fonte
0

Tente este método a seguir:

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 Part Fridjat
fonte