Làm cách nào để thay đổi kích thước hình ảnh bằng Java?


126

Tôi cần thay đổi kích thước các tệp PNG, JPEG và GIF. Làm thế nào tôi có thể làm điều này bằng cách sử dụng Java?


14
vì bạn đã yêu cầu một thư viện, câu trả lời thực sự nằm ở đây: stackoverflow.com/questions/244164/ . Nó dễ sử dụng hơn nhiều so với mã trong câu trả lời được chấp nhận;)
Artur Gajowy

Tôi không đồng ý về phần thư viện: Graphics2D là một phần của thư viện awt và nó là nguồn mở. Đối với phần cuối cùng (nguồn mở) tôi không chắc chắn 100%, nhưng ai sẽ xem mã awt nào?
Burkhard

Câu trả lời:


87

Sau khi tải hình ảnh, bạn có thể thử:

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
Tôi thấy kỹ thuật này tạo ra một hình ảnh không đủ chất lượng cho nhu cầu của tôi.
morgancodes

1
Image.getScaledInstance (chiều rộng, chiều cao, gợi ý) cũng sẽ làm gì?
kịch bản

1
Kiểm tra AlAla có sai cách không (đối với imageType)?
Thilo

Tôi đồng ý với @morgancodes. Chất lượng hình ảnh kém hơn nhiều so với những gì bạn nhận được với OS X Preview khi thay đổi kích thước theo cùng kích thước. Sẽ thử một số thư viện nguồn mở để xem liệu chúng có giá tốt hơn không.
Thilo

1
"Sẽ thử một số thư viện nguồn mở để xem liệu chúng có giá tốt hơn không." +1 cho imgscalr từ câu trả lời của @ RiyadKalla.
Thilo

182

FWIW Tôi vừa phát hành (Apache 2, được lưu trữ trên GitHub) một thư viện chia tỷ lệ hình ảnh đơn giản cho Java có tên là imgscalr (có sẵn trên trung tâm Maven ).

Thư viện triển khai một vài cách tiếp cận khác nhau để nhân rộng hình ảnh (bao gồm cả cách tiếp cận gia tăng của Chris Campbell với một vài cải tiến nhỏ) và sẽ chọn cách tiếp cận tối ưu nhất cho bạn nếu bạn hỏi nó, hoặc cho bạn cách nhìn nhanh nhất hoặc tốt nhất (nếu bạn yêu cầu điều đó).

Cách sử dụng rất đơn giản, chỉ là một loạt các phương thức tĩnh. Trường hợp sử dụng đơn giản nhất là:

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

Tất cả các thao tác đều duy trì tỷ lệ ban đầu của hình ảnh, vì vậy trong trường hợp này, bạn đang yêu cầu imgscalr thay đổi kích thước hình ảnh của bạn trong phạm vi rộng 200 pixel và cao 200 pixel và theo mặc định, nó sẽ tự động chọn cách tiếp cận nhanh nhất và đẹp nhất cho nó. 'được chỉ định.

Tôi nhận ra ngay từ đầu, nó trông giống như tự quảng cáo (nhưng nó), nhưng tôi đã dành thời gian chia sẻ công bằng chính xác chủ đề này và tiếp tục đưa ra các kết quả / cách tiếp cận / suy nghĩ / đề xuất khác nhau và quyết định ngồi xuống và viết triển khai đơn giản sẽ giải quyết 80-85% trường hợp sử dụng mà bạn có hình ảnh và có thể muốn có hình thu nhỏ cho nó - nhanh nhất có thể hoặc đẹp nhất có thể (đối với những người đã thử, bạn sẽ nhận thấy thực hiện Graphics.drawImage ngay cả với phép nội suy BICUBIC thành một hình ảnh đủ nhỏ, nó vẫn trông giống như rác).


1
Riyad, tôi thích sử dụng Scalr. Tôi tò mò muốn biết, cuối cùng bạn đã chọn một API bằng tất cả các phương thức tĩnh như thế nào? Tôi đã viết một api tương tự gần gũi hơn với một người xây dựng. Thích new ImageScaler(img).resizeTo(...).rotate(...).cropTo(...).toOutputBuffer(). Tôi cũng thích cách của bạn và tôi nghĩ nó đơn giản hơn.
Amir Raminfar

4
Amir, các mô hình xây dựng các công trình tuyệt vời cho các loại thư viện là tốt, tôi chỉ tình cờ đi với cách tiếp cận tĩnh-method vì tôi nghĩ đó là một mái tóc dễ dàng hơn để làm theo cho người dùng mới và việc sử dụng-pattern tôi mong đợi từ imgscalr (ban đầu chỉ các phương thức thay đổi kích thước duy nhất) không được hưởng lợi từ việc có trạng thái giữ cá thể (Phiên bản trình tạo). Vì vậy, tôi đã lưu vào đối tượng khởi tạo và đi với các phương thức tĩnh. Tôi đã có lập trường mạnh mẽ chống lại việc tạo đối tượng bên trong imgscalr ở mọi nơi tôi có thể tránh được. Cả hai cách tiếp cận đều làm việc tuyệt vời.
Riyad Kalla

5
+1 để cung cấp tính năng này trên kho lưu trữ Maven trung tâm!
Grilse

Lớp BufferedImage này là gì, tại sao studio android không tìm thấy nó? @Riyad Kalla
Milad

3
@ xe4me BufferedImage là một lớp trong J2SE JDK (một phần của khung Java2D) được sử dụng để biểu diễn dữ liệu pixel thô, không nén. Nó không có sẵn trên Android, Android cung cấp các lớp riêng để làm việc với dữ liệu hình ảnh.
Riyad Kalla

54

Thumbnailator là một thư viện thay đổi kích thước hình ảnh nguồn mở cho Java với giao diện lưu loát, được phân phối theo giấy phép MIT.

Tôi đã viết thư viện này bởi vì việc tạo các hình thu nhỏ chất lượng cao trong Java có thể khó khăn một cách đáng ngạc nhiên và mã kết quả có thể khá lộn xộn. Với Thumbnailator, có thể thể hiện các tác vụ khá phức tạp bằng cách sử dụng API trôi chảy đơn giản.

Một ví dụ đơn giản

Ví dụ đơn giản, lấy một hình ảnh và thay đổi kích thước của nó thành 100 x 100 (giữ nguyên tỷ lệ khung hình của ảnh gốc) và lưu nó vào một tệp có thể đạt được trong một câu lệnh:

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

Một ví dụ nâng cao

Thực hiện các tác vụ thay đổi kích thước phức tạp được đơn giản hóa với giao diện lưu loát của Thumbnailator.

Giả sử chúng ta muốn làm như sau:

  1. lấy hình ảnh trong một thư mục và,
  2. thay đổi kích thước chúng thành 100 x 100, với tỷ lệ khung hình của ảnh gốc,
  3. lưu tất cả chúng vào JPEG với các cài đặt chất lượng của 0.85,
  4. trong đó tên tệp được lấy từ bản gốc có thumbnail.gắn vào đầu

Được dịch sang Thumbnailator, chúng tôi có thể thực hiện những điều trên với những điều sau:

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

Một lưu ý về chất lượng và tốc độ hình ảnh

Thư viện này cũng sử dụng phương pháp chia tỷ lệ lũy tiến lũy tiến được tô sáng trong Filthy Rich Client của Chet Haase và Romain Guy để tạo hình thu nhỏ chất lượng cao trong khi vẫn đảm bảo hiệu suất thời gian chạy chấp nhận được.


1
coobird, công việc thực sự tốt đẹp với API. Rất thẳng về phía trước và dễ sử dụng.
Riyad Kalla

@LordT: Tôi rất vui vì bạn thấy Thumbnailator dễ sử dụng :)
coobird

Làm cách nào tôi có thể tạo hình thu nhỏ 80x80 với hình ảnh gốc 500x400? tôi đã không thấy bất kỳ lựa chọn cho nó. cảm ơn!
terry

".OoutputFormat (" JPEG ")" không được ghi trong tài liệu.
Vincent Cantin

@Vincent Danh sách đầy đủ các phương thức có thể được sử dụng có trong Tài liệu API của Thumbnailator
Thumbator.googlecode.com/hg/javadoc/net/coobird/ tựa

12

Bạn không cần một thư viện để làm điều này. Bạn có thể làm điều đó với chính Java.

Chris Campbell có một bài viết tuyệt vời và chi tiết về tỷ lệ hình ảnh - xem bài viết này .

Chet Haase và Romain Guy cũng có một bài viết chi tiết và rất nhiều thông tin về nhân rộng hình ảnh trong cuốn sách của họ, Khách hàng giàu có bẩn thỉu .


7
Bài viết của Chris chính xác là điều thúc đẩy tôi viết imgscalr ngay từ đầu; và những câu hỏi như thế này (và câu trả lời như của bạn). Rất nhiều người hỏi đi hỏi lại nhiều lần làm thế nào để có được hình thu nhỏ đẹp mắt từ một hình ảnh. Có một số cách để làm điều đó, Chris không phải lúc nào cũng là cách tốt nhất, nó phụ thuộc vào những gì bạn đang cố gắng thực hiện và mức giảm lớn như thế nào. imgscalr giải quyết tất cả điều đó và đó là 1 lớp.
Riyad Kalla

2
+1, tôi đồng ý, khách hàng của Filthy Rich là một trong những cuốn sách java hay nhất hiện có ngang với "java hiệu quả", nhưng ImgScalr là thứ tôi sử dụng vì tôi lười biếng.
Shawn Vader


9

Nếu bạn đang xử lý các hình ảnh lớn hoặc muốn có một kết quả đẹp mắt thì đó không phải là một nhiệm vụ tầm thường trong java. Chỉ cần thực hiện thông qua opcale op thông qua Graphics2D sẽ không tạo ra hình thu nhỏ chất lượng cao. Bạn có thể làm điều đó bằng cách sử dụng JAI, nhưng nó đòi hỏi nhiều công việc hơn bạn tưởng để có được thứ gì đó có vẻ tốt và JAI có thói quen khó chịu khi thổi JVM của chúng tôi với các lỗi OutOfMemory.

Tôi đề nghị sử dụng ImageMagick như một tệp thực thi bên ngoài nếu bạn có thể thoát khỏi nó. Nó đơn giản để sử dụng và nó thực hiện đúng công việc mà bạn không phải làm.


4

Nếu, có cài đặt hình ảnh trên maschine của bạn là một tùy chọn, tôi khuyên dùng im4java . Nó là một lớp trừu tượng rất mỏng trên giao diện dòng lệnh, nhưng thực hiện công việc của nó rất tốt.


3

API Java không cung cấp tính năng chia tỷ lệ chuẩn cho hình ảnh và hạ thấp chất lượng hình ảnh.

Vì điều này tôi đã cố gắng sử dụng cvResize từ JavaCV nhưng dường như nó gây ra sự cố.

Tôi đã tìm thấy một thư viện tốt để chia tỷ lệ hình ảnh: chỉ cần thêm phụ thuộc cho "java-image-scaleing" trong tệp pom.xml của bạn.

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

Trong kho lưu trữ maven, bạn sẽ nhận được phiên bản gần đây cho việc này.

Ví dụ. Trong chương trình java của bạn

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

Nó cũng có sẵn trên GitHub ( github.com/mortennobel/java-image-scaling.git ) và hiện tại nó đã có phiên bản 8.7. Nó cần sửa lỗi trong pom.xml, bạn (thay đổi nguồn và đích thành ít nhất 1.6 vì Maven mới hơn không hỗ trợ 1.5 nữa).
Cromax

2

Bạn có thể thử sử dụng Hệ thống xử lý ảnh GraphicsMagick với im4java làm giao diện comand-line cho Java.

Có rất nhiều lợi thế của GraphicsMagick, nhưng một ưu điểm cho tất cả:

  • GM được sử dụng để xử lý hàng tỷ tệp tại các trang ảnh lớn nhất thế giới (ví dụ Flickr và Etsy).

1

Hình ảnh Magick đã được đề cập. Có một dự án kết thúc trước JNI được gọi là JMagick. Đây không phải là một dự án đặc biệt ổn định (và Image Magick đã được biết là thay đổi rất nhiều và thậm chí phá vỡ tính tương thích). Điều đó nói rằng, chúng tôi đã có kinh nghiệm tốt khi sử dụng JMagick và một phiên bản tương thích của Image Magick trong môi trường sản xuất để thực hiện mở rộng ở tốc độ cao, tốc độ trễ thấp. Tốc độ tốt hơn đáng kể sau đó với một thư viện đồ họa Java mà chúng tôi đã thử trước đây.

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


1

Chỉ cần sử dụng câu trả lời của Burkhard nhưng thêm dòng này sau khi tạo đồ họa:

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

Bạn cũng có thể đặt giá trị thành BICUBIC, nó sẽ tạo ra hình ảnh chất lượng tốt hơn nhưng là một hoạt động đắt tiền hơn. Có những gợi ý kết xuất khác mà bạn có thể đặt nhưng tôi đã thấy rằng phép nội suy tạo ra hiệu ứng đáng chú ý nhất. Hãy ghi nhớ nếu bạn muốn phóng to nhiều, mã java rất có thể sẽ rất chậm. Tôi thấy hình ảnh lớn hơn bắt đầu tạo ra độ trễ khoảng 300% thu phóng ngay cả với tất cả các gợi ý kết xuất được đặt để tối ưu hóa cho tốc độ trên chất lượng.



1

Nó chỉ ra rằng viết một bộ thu nhỏ hiệu suất không phải là nhỏ. Tôi đã làm điều đó một lần cho một dự án nguồn mở: ImageScaler .

Về nguyên tắc 'java.awt.Image # getScaledInstance (int, int, int)' cũng sẽ thực hiện công việc này, nhưng có một lỗi khó chịu với điều này - hãy tham khảo liên kết của tôi để biết chi tiết.


0

Tôi đã phát triển một giải pháp với các lớp có sẵn miễn phí (AnimatedGifEncoder, GifDecoder và LWZEncoder) có sẵn để xử lý GIF Animation.
Bạn có thể tải xuống jgifcode jar và chạy lớp GifImageUtil. Liên kết: http://www.jgifcode.com


1
Vui lòng đề cập trong câu trả lời nếu bạn liên kết với sản phẩm bạn đề xuất.
Hans Olsson

waw ... là để thay đổi kích thước hình ảnh hoạt hình GIF? và nó miễn phí ?? Wwaww ... tôi nên thử ngay bây giờ ...
gumuruh

Vâng, điều này được phát triển bởi tôi. Đây là mã nguồn cho nó github.com/rt29/jgifcode - Đây là đây. Tôi không ủng hộ nó nữa.
Rohit Tiwari


0

Nếu bạn không muốn nhập imgScalr như @Riyad Kalla trả lời ở trên mà tôi đã kiểm tra quá hoạt động tốt, bạn có thể thực hiện việc này từ Peter Walser trả lời @Peter Walser về một vấn đề khác:

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

Hãy thử phương pháp folowing này:

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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.