Come posso ridimensionare un'immagine usando Java?


126

Devo ridimensionare i file PNG, JPEG e GIF. Come posso fare questo usando Java?


14
da quando hai chiesto una biblioteca, la vera risposta è qui: stackoverflow.com/questions/244164/… . È molto più facile da usare rispetto al codice nella risposta accettata;)
Artur Gajowy

Non sono d'accordo sulla parte della biblioteca: Graphics2D fa parte della libreria awt ed è open source. Per l'ultima parte (open source) non ne sono sicuro al 100%, ma chi guarderebbe comunque il codice awt?
Burkhard,

Risposte:


87

Dopo aver caricato l'immagine puoi provare:

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;
    }

9
Ho scoperto che questa tecnica crea un'immagine che non è di qualità sufficientemente elevata per le mie esigenze.
morgancodes,

1
farà Image.getScaledInstance (larghezza, altezza, suggerimenti)?
codice

1
è il controllo keepAlpha nel modo sbagliato (per imageType)?
Thilo,

Sono d'accordo con @morgancodes. La qualità dell'immagine è molto peggiore di quella ottenuta ad esempio con l'anteprima di OS X quando si ridimensiona alle stesse dimensioni. Proverò alcune librerie open-source per vedere se funzionano meglio.
Thilo,

1
"Proverò alcune librerie open-source per vedere se funzionano meglio." +1 per imgscalr dalla risposta di @ RiyadKalla.
Thilo,

182

FWIW Ho appena rilasciato (Apache 2, ospitato su GitHub) una semplice libreria di ridimensionamento delle immagini per Java chiamata imgscalr (disponibile su Maven central ).

La libreria implementa alcuni approcci diversi al ridimensionamento delle immagini (incluso l'approccio incrementale di Chris Campbell con alcuni miglioramenti minori) e sceglierà l'approccio ottimale per te se lo chiedi, o ti darà l'aspetto più veloce o migliore (se chiedere quello).

L'uso è semplicissimo, solo un mucchio di metodi statici. Il caso d'uso più semplice è:

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

Tutte le operazioni mantengono le proporzioni originali dell'immagine, quindi in questo caso stai chiedendo a imgscalr di ridimensionare l'immagine entro un limite di 200 pixel di larghezza e 200 pixel di altezza e per impostazione predefinita selezionerà automaticamente l'approccio più bello e veloce da quando non lo era non specificato.

All'inizio mi rendo conto che sembra un'autopromozione (lo è), ma ho trascorso la mia giusta parte del tempo a cercare su Google questo stesso identico argomento e ho continuato a trovare risultati / approcci / pensieri / suggerimenti diversi e ho deciso di sedermi e scrivere un semplice implementazione che indirizzerebbe quei casi d'uso dell'80-85% in cui hai un'immagine e probabilmente desideri una miniatura per essa - il più velocemente possibile o il più bello possibile (per quelli che hanno provato, noterai facendo un Graphics.drawImage anche con interpolazione BICUBIC su un'immagine abbastanza piccola, sembra ancora spazzatura).


1
Riyad, mi è piaciuto usare Scalr. Sono curioso di sapere, come hai fatto a scegliere un'API con tutti i metodi statici? Avevo scritto un'API simile che era più vicina a un costruttore. Come new ImageScaler(img).resizeTo(...).rotate(...).cropTo(...).toOutputBuffer(). Mi piace anche la tua strada e penso che sia più semplice.
Amir Raminfar,

4
Amir, il modello di generatore funziona meravigliosamente anche per questi tipi di librerie, mi è capitato di seguire l'approccio del metodo statico perché pensavo fosse un pelo più facile da seguire per i nuovi utenti e il modello di utilizzo che mi aspettavo da imgscalr (originariamente solo i metodi di ridimensionamento singolo) non hanno beneficiato della presenza di uno stato di conservazione dell'istanza (istanza del builder). Quindi ho salvato l'istanza dell'oggetto e sono andato con i metodi statici. Ho preso una posizione forte contro la creazione di oggetti all'interno di imgscalr in ogni luogo in cui posso evitarlo. Entrambi gli approcci funzionano benissimo però.
Riyad Kalla,

5
+1 per averlo reso disponibile nel repository Maven centrale!
Grilse,

Cos'è questa classe BufferedImage, perché Android Studio non la trova? @Riyad Kalla
Milad

3
@ xe4me BufferedImage è una classe nel JDK J2SE (parte del framework Java2D) utilizzata per rappresentare dati pixel grezzi e non compressi. Non è disponibile su Android, Android fornisce le proprie classi per lavorare con i dati delle immagini.
Riyad Kalla,

54

Thumbnailator è una libreria di ridimensionamento di immagini open source per Java con un'interfaccia fluida, distribuita con licenza MIT.

Ho scritto questa libreria perché realizzare miniature di alta qualità in Java può essere sorprendentemente difficile e il codice risultante potrebbe essere piuttosto disordinato. Con Thumbnailator, è possibile esprimere compiti abbastanza complicati usando una semplice API fluente.

Un semplice esempio

Per un semplice esempio, prendere un'immagine e ridimensionarla a 100 x 100 (preservare le proporzioni dell'immagine originale) e salvarla in un file può essere ottenuta in una singola istruzione:

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

Un esempio avanzato

L'esecuzione di attività di ridimensionamento complesse è semplificata dall'interfaccia fluida di Thumbnailator.

Supponiamo di voler fare quanto segue:

  1. prendere le immagini in una directory e,
  2. ridimensionali a 100 x 100, con le proporzioni dell'immagine originale,
  3. salvarli tutti in JPEG con impostazioni di qualità di 0.85,
  4. dove i nomi dei file sono presi dall'originale con l' thumbnail.aggiunta all'inizio

Tradotto in Thumbnailator, saremmo in grado di eseguire quanto sopra con il seguente:

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

Una nota sulla qualità e la velocità dell'immagine

Questa libreria utilizza anche il metodo di ridimensionamento bilineare progressivo evidenziato in Filthy Rich Clients da Chet Haase e Romain Guy al fine di generare miniature di alta qualità garantendo prestazioni di runtime accettabili.


1
coobird, lavoro davvero carino con l'API. Molto semplice e facile da usare.
Riyad Kalla,

@LordT: Sono contento che tu abbia trovato Thumbnailator facile da usare :)
coobird

Come posso creare una miniatura 80x80 con un'immagine originale 500x400? non ho visto alcuna opzione per questo. Grazie!
Terry,

".outputFormat (" JPEG ")" non è scritto da nessuna parte nella documentazione.
Vincent Cantin,

@Vincent L'elenco completo dei metodi che è possibile utilizzare si trova nella documentazione dell'API Thumbnailator - thumbnailator.googlecode.com/hg/javadoc/net/coobird/…
coobird

12

Non hai bisogno di una biblioteca per farlo. Puoi farlo con Java stesso.

Chris Campbell ha una descrizione eccellente e dettagliata delle immagini in scala: leggi questo articolo .

Chet Haase e Romain Guy hanno anche una descrizione dettagliata e molto istruttiva del ridimensionamento delle immagini nel loro libro, Filthy Rich Clients .


7
L'articolo di Chris è esattamente ciò che mi ha motivato a scrivere imgscalr in primo luogo; e domande come questa (e risposte come le tue). Molte persone chiedono ancora e ancora e ancora come ottenere miniature di bell'aspetto da un'immagine. Ci sono molti modi per farlo, quello di Chris non è sempre il modo migliore, dipende da cosa stai cercando di fare e da quanto è grande la riduzione. imgscalr risolve tutto ciò ed è 1 classe.
Riyad Kalla,

2
+1, sono d'accordo, i clienti di Filthy Rich sono uno dei migliori libri di java disponibili alla pari di "java efficace", ma ImgScalr è ciò che uso perché sono pigro.
Shawn Vader


9

Se hai a che fare con immagini di grandi dimensioni o desideri un risultato piacevole, non è un compito banale in Java. La semplice esecuzione tramite un'operazione di ridimensionamento tramite Graphics2D non crea un'anteprima di alta qualità. Puoi farlo usando JAI, ma richiede più lavoro di quanto tu possa immaginare per ottenere qualcosa che abbia un bell'aspetto e JAI ha la brutta abitudine di far esplodere la tua JVM con errori OutOfMemory.

Suggerisco di usare ImageMagick come eseguibile esterno se riesci a cavartela. È semplice da usare e fa bene il lavoro in modo da non doverlo fare.


4

Se, avendo imagemagick installato sulla tua macchina è un'opzione, ti consiglio im4java . È un livello di astrazione molto sottile sull'interfaccia della riga di comando, ma fa molto bene il suo lavoro.


3

L'API Java non fornisce una funzionalità di ridimensionamento standard per le immagini e il downgrade della qualità delle immagini.

Per questo motivo ho provato ad usare cvResize da JavaCV ma sembra causare problemi.

Ho trovato una buona libreria per il ridimensionamento delle immagini: aggiungi semplicemente la dipendenza per "ridimensionamento delle immagini java" nel tuo pom.xml.

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

Nel repository Maven otterrai la versione recente per questo.

Ex. Nel tuo programma Java

ResampleOp resamOp = new ResampleOp(50, 40);
BufferedImage modifiedImage = resamOp.filter(originalBufferedImage, null);

È anche disponibile su GitHub ( github.com/mortennobel/java-image-scaling.git ) e ha la versione 8.7 per ora. Aveva bisogno di una correzione in pom.xml, tu (cambiando sorgente e destinazione ad almeno 1.6 poiché Maven più recente non supporta più 1.5).
Cromax,

2

Potresti provare a utilizzare GraphicsMagick Image Processing System con im4java come interfaccia a riga di comando per Java.

Ci sono molti vantaggi di GraphicsMagick, ma uno per tutti:

  • GM viene utilizzato per elaborare miliardi di file nei siti di foto più grandi del mondo (ad esempio Flickr ed Etsy).

1

Image Magick è stato menzionato. Esiste un progetto front-end JNI chiamato JMagick. Non è un progetto particolarmente stabile (e Image Magick stesso è noto per cambiare molto e persino rompere la compatibilità). Detto questo, abbiamo avuto una buona esperienza nell'uso di JMagick e di una versione compatibile di Image Magick in un ambiente di produzione per eseguire il ridimensionamento con un throughput elevato e un basso tasso di latenza. La velocità era sostanzialmente migliore rispetto a una libreria grafica tutta Java che avevamo già provato.

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


1

Usa semplicemente la risposta di Burkhard ma aggiungi questa riga dopo aver creato la grafica:

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

Puoi anche impostare il valore su BICUBIC, produrrà un'immagine di qualità migliore ma è un'operazione più costosa. Ci sono altri suggerimenti per il rendering che puoi impostare ma ho scoperto che l'interpolazione produce l'effetto più notevole. Tieni a mente se vuoi ingrandire molto, il codice java molto probabilmente sarà molto lento. Trovo che immagini più grandi inizino a produrre un ritardo di circa il 300% di zoom anche con tutti i suggerimenti di rendering impostati per ottimizzare la velocità rispetto alla qualità.



1

Si scopre che scrivere uno scaler performante non è banale. L'ho fatto una volta per un progetto open source: ImageScaler .

In linea di principio 'java.awt.Image # getScaledInstance (int, int, int)' farebbe anche il lavoro, ma c'è un brutto bug con questo - fare riferimento al mio link per i dettagli.


0

Ho sviluppato una soluzione con le classi liberamente disponibili (AnimatedGifEncoder, GifDecoder e LWZEncoder) disponibili per gestire l'animazione GIF.
È possibile scaricare il jgifcode jar ed eseguire la classe GifImageUtil. Link: http://www.jgifcode.com


1
Indicare nella risposta se si è affiliati al prodotto che si consiglia.
Hans Olsson,

waw ... è per ridimensionare l'immagine animata GIF? ed è gratis ?? Wwaww ... dovrei provarlo adesso ...
gumuruh,

Sì, questo è stato sviluppato da me. Ecco il codice sorgente per esso github.com/rt29/jgifcode - Questo è ora qui. Non lo sto più supportando.
Rohit Tiwari,


0

Se non vuoi importare imgScalr come la risposta @Riyad Kalla sopra la quale ho testato troppo funziona bene, puoi farlo preso da Peter Walser rispondere @Peter Walser su un altro problema però:

 /**
     * 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;
        }
    }

0

Prova questo metodo folowing:

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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.