Java kullanarak bir resmi nasıl yeniden boyutlandırabilirim?


126

PNG, JPEG ve GIF dosyalarını yeniden boyutlandırmam gerekiyor. Bunu Java kullanarak nasıl yapabilirim?


14
bir kitaplık istemiş olduğunuz için, gerçek yanıt burada: stackoverflow.com/questions/244164/… . Kabul edilen cevaptaki koddan çok daha kolay;)
Artur Gajowy

Kütüphane kısmına katılmıyorum: Graphics2D, awt kütüphanesinin bir parçası ve açık kaynak. Son kısım için (açık kaynak)% 100 emin değilim, ama yine de awt koduna kim bakar?
Burkhard

Yanıtlar:


87

Resmi yükledikten sonra deneyebilirsiniz:

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
Bu tekniğin ihtiyaçlarım için yeterince yüksek kalitede olmayan bir görüntü oluşturduğunu buldum.
morgancodes

1
Image.getScaledInstance (genişlik, yükseklik, ipuçları) da işe yarar mı?
codeplay

1
preserveAlpha kontrolü yanlış mı (imageType için)?
Thilo

@Morgancodes'e katılıyorum. Görüntü kalitesi, örneğin OS X Önizleme ile aynı boyutlara yeniden boyutlandırırken elde ettiğinizden çok daha kötüdür. Daha iyi olup olmadıklarını görmek için bazı açık kaynak kitaplıkları deneyecek.
Thilo

1
"Daha iyi olup olmadıklarını görmek için bazı açık kaynaklı kütüphaneleri deneyecek." @ RiyadKalla'nın cevabından imgscalr için +1.
Thilo

182

FWIW Java için imgscalr ( Maven merkezinde mevcuttur) adında basit bir görüntü ölçekleme kitaplığı yayınladım (GitHub'da barındırılan Apache 2 ).

Kütüphane, görüntü ölçeklendirmeye birkaç farklı yaklaşım uygular (Chris Campbell'in birkaç küçük geliştirmeyle artan yaklaşımı dahil) ve isterseniz sizin için en uygun yaklaşımı seçer veya size en hızlı veya en iyi görünümü verir (eğer bunu isteyin).

Kullanım son derece basittir, sadece birkaç statik yöntemdir. En basit kullanım durumu şudur:

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

Tüm işlemler görüntünün orijinal oranlarını korur, bu durumda imgscalr'dan görüntünüzü 200 piksel genişliğinde ve 200 piksel uzunluğunda sınırlar içinde yeniden boyutlandırmasını istiyorsunuz ve varsayılan olarak otomatik olarak bunun için en iyi görünen ve en hızlı yaklaşımı seçecektir. belirtilmedi.

Başlangıçta bunun kendi kendini tanıtmaya benzediğini fark ettim (öyle), ancak zaman payımı aynı konuyu araştırmaya harcadım ve farklı sonuçlar / yaklaşımlar / düşünceler / öneriler üretmeye devam ettim ve oturup yazmaya karar verdim. Bir resme sahip olduğunuz ve muhtemelen bunun için bir küçük resim istediğiniz% 80-85'lik kullanım durumlarına hitap edecek basit bir uygulama - ya olabildiğince hızlı ya da olabildiğince güzel (deneyenler için fark edeceksiniz yeterince küçük bir görüntüye BICUBIC enterpolasyonuyla bile Graphics.drawImage yapmak, yine de çöp gibi görünüyor).


1
Riyad, Scalr kullanmayı sevdim. Merak ediyorum, tüm statik yöntemlerle bir API seçmeye nasıl başladınız? Bir inşaatçıya daha yakın benzer bir API yazmıştım. Beğen new ImageScaler(img).resizeTo(...).rotate(...).cropTo(...).toOutputBuffer(). Ben de senin tarzını beğendim ve daha basit olduğunu düşünüyorum.
Amir Raminfar

4
Amir, kurucu kalıbı bu tür kitaplıklar için de harika çalışıyor, sadece statik yöntem yaklaşımını tercih ettim çünkü yeni kullanıcılar için takip edilmesi daha kolay bir saç ve imgscalr'dan beklediğim kullanım kalıbı (orijinal olarak yalnızca tek yeniden boyutlandırma yöntemleri), bir örnek tutma durumuna sahip olmaktan fayda sağlamadı (Oluşturucu örneği). Böylece nesne somutlaştırmasından tasarruf ettim ve statik yöntemlerle gittim. Önleyebileceğim her yerde imgscalr içinde nesne yaratmaya karşı güçlü bir duruş aldım. Her iki yaklaşım da harika çalışıyor.
Riyad Kalla

5
Bunu merkezi Maven deposunda kullanıma sunmak için +1!
Grilse

Bu BufferedImage sınıfı nedir, android studio neden bulamıyor? @Riyad Kalla
Milad

3
@ xe4me BufferedImage, ham, sıkıştırılmamış piksel verilerini temsil etmek için kullanılan J2SE JDK'da (Java2D çerçevesinin parçası) bir sınıftır. Android'de mevcut değildir, Android, görüntü verileriyle çalışmak için kendi sınıflarını sağlar.
Riyad Kalla

54

Thumbnailator , MIT lisansı altında dağıtılan, akıcı bir arayüze sahip Java için açık kaynaklı bir resim yeniden boyutlandırma kitaplığıdır .

Bu kitaplığı yazdım çünkü Java'da yüksek kaliteli küçük resimler oluşturmak şaşırtıcı derecede zor olabilir ve ortaya çıkan kod oldukça dağınık olabilir. Thumbnailator ile basit ve akıcı bir API kullanarak oldukça karmaşık görevleri ifade etmek mümkündür.

Basit bir örnek

Basit bir örnek olarak, bir görüntünün alınması ve 100 x 100'e yeniden boyutlandırılması (orijinal görüntünün en boy oranının korunarak) ve bir dosyaya kaydedilmesi tek bir ifadede gerçekleştirilebilir:

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

Gelişmiş bir örnek

Karmaşık yeniden boyutlandırma görevlerinin gerçekleştirilmesi, Thumbnailator'ın akıcı arayüzü ile basitleştirilmiştir.

Aşağıdakileri yapmak istediğimizi varsayalım:

  1. görüntüleri bir dizine alın ve
  2. bunları orijinal görüntünün en boy oranıyla 100 x 100 olarak yeniden boyutlandırın,
  3. hepsini kalite ayarlarıyla JPEG'lere kaydedin 0.85,
  4. dosya adlarının thumbnail.başa eklenmiş olarak orijinalden alındığı yer

Thumbnailator'a çevrildiğinde, yukarıdakileri aşağıdakilerle gerçekleştirebileceğiz:

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

Görüntü kalitesi ve hız hakkında bir not

Bu kitaplık aynı zamanda, kabul edilebilir çalışma zamanı performansı sağlarken yüksek kaliteli küçük resimler oluşturmak için Chet Haase ve Romain Guy tarafından Filthy Rich Clients'da vurgulanan aşamalı çift doğrusal ölçekleme yöntemini kullanır .


1
coobird, API ile gerçekten iyi iş çıkardın. Çok yalındır ve kullanımı kolaydır.
Riyad Kalla

@LordT: Thumbnailator'ı kullanımı kolay bulduğunuza sevindim :)
coobird

500x400 orijinal görüntü ile 80x80 küçük resmi nasıl oluşturabilirim? bunun için herhangi bir seçenek görmedim. Teşekkürler!
terry

".outputFormat (" JPEG ")" belgelerin hiçbir yerinde yazılmamıştır.
Vincent Cantin

@Vincent Kullanılabilecek yöntemlerin tam listesi, Thumbnailator API Dokümantasyonunda bulunmaktadır - thumbnailator.googlecode.com/hg/javadoc/net/coobird/…
coobird

12

Bunu yapmak için bir kitaplığa ihtiyacınız yok. Bunu Java'nın kendisi ile yapabilirsiniz.

Chris Campbell'ın görüntüleri ölçekleme konusunda mükemmel ve ayrıntılı bir yazısı var - bu makaleye bakın .

Chet Haase ve Romain Guy, Filthy Rich Clients adlı kitaplarında da ayrıntılı ve çok bilgilendirici bir görsel ölçeklendirme yazısına sahipler .


7
Chris'in makalesi, beni ilk başta imgscalr yazmaya motive eden şeydi; ve bunun gibi sorular (ve sizinki gibi cevaplar). Pek çok insan defalarca bir görselden nasıl güzel görünen küçük resimler çekileceğini soruyor. Bunu yapmanın birkaç yolu vardır, Chris her zaman en iyi yol değildir , ne yapmaya çalıştığınıza ve azaltmanın ne kadar büyük olduğuna bağlıdır. imgscalr tüm bunları ele alıyor ve 1. sınıf.
Riyad Kalla

2
+1, katılıyorum, Filthy Rich müşterileri "Etkili java" ile aynı seviyede olan en iyi java kitaplarından biri, Ama kullandığım şey ImgScalr çünkü tembelim.
Shawn Vader


9

Büyük resimlerle uğraşıyorsanız veya güzel görünen bir sonuç istiyorsanız, bu java'da önemsiz bir görev değildir. Bunu sadece Graphics2D üzerinden bir yeniden ölçeklendirme operasyonu aracılığıyla yapmak, yüksek kaliteli bir küçük resim oluşturmaz. Bunu JAI kullanarak yapabilirsiniz, ancak iyi görünen bir şey elde etmek için tahmin ettiğinizden daha fazla çalışma gerektirir ve JAI'nin JVM'nizi OutOfMemory hatalarıyla patlatmak gibi kötü bir alışkanlığı vardır.

Bundan kurtulabilirseniz, ImageMagick'i harici bir yürütülebilir dosya olarak kullanmanızı öneririm. Kullanımı basit ve işi doğru yapıyor, böylece sizin zorunda kalmazsınız.



3

Java API, görüntüler ve görüntü kalitesinin düşürülmesi için standart bir ölçekleme özelliği sağlamaz.

Bundan dolayı JavaCV'den cvResize kullanmaya çalıştım ama sorunlara neden oluyor gibi görünüyor.

Görüntü ölçekleme için iyi bir kitaplık buldum: pom.xml dosyanıza "java-image-scaling" bağımlılığını ekleyin.

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

Maven deposunda bunun için en son sürümü alacaksınız.

Ör. Java programınızda

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

Ayrıca GitHub'da ( github.com/mortennobel/java-image-scaling.git ) mevcuttur ve şimdilik 8.7 sürümüne sahiptir. Pom.xml'de li'l düzeltmesi gerekiyordu, thou (kaynak ve hedefi en az 1.6 olarak değiştirmek, çünkü yeni Maven artık 1.5'i desteklemiyor).
Cromax

2

GraphicsMagick Görüntü İşleme Sistemini im4java ile kullanmayı deneyebilirsiniz. Java için bir comand-line arabirimi olarak .

GraphicsMagick'in pek çok avantajı vardır, ancak hepsi için bir tane:

  • GM, dünyanın en büyük fotoğraf sitelerinde (örn. Flickr ve Etsy) milyarlarca dosyayı işlemek için kullanılır.

1

Image Magick'ten bahsedildi. JMagick adında bir JNI ön uç projesi var. Bu özellikle kararlı bir proje değil (ve Image Magick'in kendisinin de çok şey değiştirdiği ve hatta uyumluluğu bozduğu biliniyor). Bununla birlikte, yüksek verimlilikte, düşük gecikme hızında ölçeklendirme gerçekleştirmek için bir üretim ortamında JMagick'i ve Image Magick'in uyumlu bir sürümünü kullanma konusunda iyi bir deneyim yaşadık. Hız, daha önce denediğimiz tüm Java grafik kitaplığından çok daha iyiydi.

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


1

Sadece Burkhard'ın cevabını kullanın, ancak grafikleri oluşturduktan sonra bu satırı ekleyin:

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

Değeri BICUBIC olarak da ayarlayabilirsiniz, bu daha kaliteli bir görüntü üretir ancak daha pahalı bir işlemdir. Ayarlayabileceğiniz başka imge oluşturma ipuçları da var ama enterpolasyonun en dikkate değer etkiyi yarattığını buldum. Çok yakınlaştırmak istiyorsanız, java kodunun büyük olasılıkla çok yavaş olacağını unutmayın. Kaliteden daha yüksek hız için ayarlanan tüm işleme ipuçları ayarlanmış olsa bile, daha büyük görüntülerin% 300 yakınlaştırmada gecikme oluşturmaya başladığını gördüm.



1

Performanslı bir ölçekleyici yazmanın önemsiz olmadığı ortaya çıktı. Açık kaynaklı bir proje için bir kez yaptım: ImageScaler .

Prensipte 'java.awt.Image # getScaledInstance (int, int, int)' da işi yapar, ancak bununla ilgili kötü bir hata var - ayrıntılar için bağlantıma bakın.


0

GIF Animasyonu için ücretsiz olarak kullanılabilen sınıflarla (AnimatedGifEncoder, GifDecoder ve LWZEncoder) bir çözüm geliştirdim.
Jgifcode kavanozunu indirebilir ve GifImageUtil sınıfını çalıştırabilirsiniz. Bağlantı: http://www.jgifcode.com


1
Lütfen tavsiye ettiğiniz ürünle ilişkiniz olup olmadığını cevapta belirtin.
Hans Olsson

waw ... bu, GIF Animasyonlu resmi yeniden boyutlandırmak için mi? ve ücretsiz ?? Wwaww ... şimdi denemeliyim ...
gumuruh

Evet bu benim tarafımdan geliştirildi. İşte bunun kaynak kodu github.com/rt29/jgifcode - Bu şimdi burada. Ben artık onu desteklemiyorum.
Rohit Tiwari


0

İçe istemiyorsanız imgScalr i test yukarıda @Riyad Kalla cevap gibi çok ince, sen alınan yapabilirsiniz çalışır Peter Walser cevabı başka bir sorun olsa üzerinde @Peter Walser:

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

Aşağıdaki yöntemi deneyin:

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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.