ฉันจะปรับขนาดรูปภาพโดยใช้ Java ได้อย่างไร


126

ฉันต้องการปรับขนาดไฟล์ PNG, JPEG และ GIF ฉันจะทำสิ่งนี้โดยใช้ Java ได้อย่างไร?


14
เนื่องจากคุณถามหาห้องสมุดคำตอบที่แท้จริงอยู่ที่นี่: stackoverflow.com/questions/244164/… . ใช้ง่ายกว่ารหัสในคำตอบที่ยอมรับ;)
Artur Gajowy

ฉันไม่เห็นด้วยในส่วนของไลบรารี: Graphics2D เป็นส่วนหนึ่งของไลบรารี awt และเป็นโอเพ่นซอร์ส สำหรับส่วนสุดท้าย (โอเพ่นซอร์ส) ฉันไม่แน่ใจ 100% แต่ใครจะดูรหัส awt ล่ะ
Burkhard

คำตอบ:


87

หลังจากโหลดภาพคุณสามารถลอง:

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
ฉันพบว่าเทคนิคนี้สร้างภาพที่มีคุณภาพไม่สูงพอสำหรับความต้องการของฉัน
morgancodes

1
Image.getScaledInstance (ความกว้างความสูงคำใบ้) จะทำอย่างไร
codeplay

1
PreserveAlpha ตรวจสอบผิดวิธีหรือไม่ (สำหรับ imageType)
Thilo

ฉันเห็นด้วยกับ @morgancodes คุณภาพของภาพแย่กว่าที่คุณได้รับจากตัวอย่าง OS X Preview เมื่อปรับขนาดเป็นขนาดเดียวกัน จะลองใช้ไลบรารีโอเพนซอร์สเพื่อดูว่ามีค่าใช้จ่ายดีขึ้นหรือไม่
Thilo

1
"จะลองใช้ไลบรารีโอเพนซอร์สบ้างเพื่อดูว่าดีขึ้นไหม" +1 สำหรับ imgscalr จากคำตอบของ @ RiyadKalla
Thilo

182

FWIW ฉันเพิ่งเปิดตัว (Apache 2 โฮสต์บน GitHub) ไลบรารีการปรับขนาดภาพอย่างง่ายสำหรับ Java ที่เรียกว่าimgscalr (มีอยู่ในMaven central )

ไลบรารีใช้วิธีการต่างๆในการปรับขนาดภาพ (รวมถึงแนวทางที่เพิ่มขึ้นของ Chris Campbell ด้วยการปรับปรุงเล็กน้อยเล็กน้อย) และจะเลือกแนวทางที่เหมาะสมที่สุดสำหรับคุณหากคุณขอหรือให้วิธีที่เร็วที่สุดหรือดูดีที่สุด (ถ้าคุณ ขอที่).

การใช้งานนั้นง่ายมากเพียงแค่มีวิธีการคงที่มากมาย กรณีการใช้งานที่ง่ายที่สุดคือ:

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

การดำเนินการทั้งหมดจะรักษาสัดส่วนเดิมของภาพดังนั้นในกรณีนี้คุณขอให้ imgscalr ปรับขนาดภาพของคุณภายในขอบเขตกว้าง 200 พิกเซลและสูง 200 พิกเซลและโดยค่าเริ่มต้นระบบจะเลือกแนวทางที่ดูดีที่สุดและเร็วที่สุดสำหรับสิ่งนั้นโดยอัตโนมัติเนื่องจากไม่มี ไม่ได้ระบุ

ฉันตระหนักดีว่าในตอนแรกสิ่งนี้ดูเหมือนการโปรโมตตัวเอง (มัน) แต่ฉันใช้เวลาส่วนแบ่งที่ยุติธรรมในการเรียนรู้เรื่องเดียวกันนี้และยังคงได้ผลลัพธ์ / แนวทาง / ความคิด / ข้อเสนอแนะที่แตกต่างออกไปและตัดสินใจนั่งลงและเขียน การใช้งานที่เรียบง่ายซึ่งจะกล่าวถึงกรณีการใช้งาน 80-85% ที่คุณมีภาพและอาจต้องการภาพขนาดย่อสำหรับภาพนั้นโดยเร็วที่สุดหรือดูดีที่สุดเท่าที่จะทำได้ (สำหรับผู้ที่ได้ลองใช้แล้วคุณจะสังเกตเห็น การทำ Graphics.drawImage แม้จะมีการแก้ไข BICUBIC ให้เป็นภาพที่เล็กพอ แต่ก็ยังดูเหมือนขยะ)


1
ริยาดฉันชอบใช้ Scalr ฉันอยากรู้ว่าคุณเลือก API ด้วยวิธีการคงที่ทั้งหมดได้อย่างไร ฉันได้เขียน api ที่คล้ายกันซึ่งใกล้เคียงกับตัวสร้างมากขึ้น ชอบnew ImageScaler(img).resizeTo(...).rotate(...).cropTo(...).toOutputBuffer(). ฉันชอบวิธีของคุณเหมือนกันและฉันคิดว่ามันง่ายกว่า
Amir Raminfar

4
อาเมียร์รูปแบบการสร้างงานเยี่ยมยอดสำหรับประเภทนี้ของห้องสมุดเช่นกันฉันเพิ่งเกิดขึ้นไปด้วยวิธีการคงวิธีการเพราะผมคิดว่ามันเป็นผมที่ง่ายต่อการปฏิบัติตามสำหรับผู้ใช้ใหม่และการใช้งานรูปแบบที่ผมคาดหวังจาก imgscalr ( แต่เดิม วิธีการปรับขนาดเดียวเท่านั้น) ไม่ได้รับประโยชน์จากการมีสถานะการถืออินสแตนซ์ (อินสแตนซ์ตัวสร้าง) ดังนั้นฉันจึงบันทึกในการสร้างอินสแตนซ์วัตถุและใช้วิธีคงที่ ฉันมีจุดยืนที่แข็งแกร่งในการต่อต้านการสร้างวัตถุภายใน imgscalr ในทุกที่ที่ฉันสามารถหลีกเลี่ยงได้ ทั้งสองวิธีทำงานได้ดีแม้ว่า
Riyad Kalla

5
+1 เพื่อให้สิ่งนี้พร้อมใช้งานบนที่เก็บ Maven กลาง!
Grilse

คลาส BufferedImage นี้คืออะไรทำไม android studio หาไม่เจอ @Riyad Kalla
Milad

3
@ xe4me BufferedImage เป็นคลาสใน J2SE JDK (ส่วนหนึ่งของเฟรมเวิร์ก Java2D) ที่ใช้เพื่อแสดงข้อมูลพิกเซลดิบที่ไม่มีการบีบอัด ไม่มีให้บริการบน Android Android มีคลาสของตัวเองเพื่อทำงานกับข้อมูลรูปภาพ
Riyad Kalla

54

Thumbnailatorเป็นไลบรารีการปรับขนาดรูปภาพแบบโอเพนซอร์สสำหรับ Java พร้อมอินเทอร์เฟซที่คล่องแคล่วซึ่งเผยแพร่ภายใต้ลิขสิทธิ์ MIT

ฉันเขียนไลบรารีนี้เนื่องจากการสร้างภาพขนาดย่อคุณภาพสูงใน Java อาจเป็นเรื่องยากอย่างน่าประหลาดใจและโค้ดที่ได้ก็อาจจะยุ่งเหยิง ด้วย Thumbnailator เป็นไปได้ที่จะแสดงงานที่ค่อนข้างซับซ้อนโดยใช้ API ที่เรียบง่าย

ตัวอย่างง่ายๆ

ตัวอย่างง่ายๆเช่นการถ่ายภาพและปรับขนาดเป็น 100 x 100 (รักษาอัตราส่วนของภาพต้นฉบับ) และบันทึกลงในไฟล์สามารถทำได้ในคำสั่งเดียว:

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

ตัวอย่างขั้นสูง

การดำเนินการปรับขนาดที่ซับซ้อนได้ง่ายขึ้นด้วยอินเทอร์เฟซที่คล่องแคล่วของ Thumbnailator

สมมติว่าเราต้องการทำสิ่งต่อไปนี้:

  1. ถ่ายภาพในไดเรกทอรีและ
  2. ปรับขนาดเป็น 100 x 100 ด้วยอัตราส่วนภาพของภาพต้นฉบับ
  3. บันทึกทั้งหมดเป็น JPEG ด้วยการตั้งค่าคุณภาพของไฟล์ 0.85 ,
  4. โดยที่ชื่อไฟล์ถูกนำมาจากต้นฉบับด้วย thumbnail.ต่อท้าย

แปลเป็น Thumbnailator เราจะสามารถดำเนินการดังต่อไปนี้:

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

หมายเหตุเกี่ยวกับคุณภาพและความเร็วของภาพ

ไลบรารีนี้ยังใช้วิธีการปรับขนาดทวิภาคีแบบโปรเกรสซีฟที่ไฮไลต์ในFilthy Rich Clientsโดย Chet Haase และ Romain Guy เพื่อสร้างภาพขนาดย่อที่มีคุณภาพสูงในขณะที่รับประกันประสิทธิภาพรันไทม์ที่ยอมรับได้


1
coobird เป็นงานที่ดีจริงๆกับ API ตรงไปตรงมามากและใช้งานง่าย
Riyad Kalla

@LordT: ฉันดีใจที่คุณพบว่า Thumbnailator ใช้งานง่าย :)
coobird

ฉันจะสร้างภาพขนาดย่อ 80x80 ด้วยภาพต้นฉบับ 500x400 ได้อย่างไร ฉันไม่เห็นตัวเลือกใด ๆ สำหรับมัน ขอบคุณ!
เทอร์รี่

".outputFormat (" JPEG ")" ไม่ได้เขียนไว้ที่ใดในเอกสาร
Vincent Cantin

@ Vincent รายการวิธีการทั้งหมดที่สามารถใช้ได้อยู่ในเอกสาร Thumbnailator API - ขนาดย่อ
googlecode.com/hg/javadoc/net/coobird/…

12

คุณไม่จำเป็นต้องมีห้องสมุดเพื่อทำสิ่งนี้ คุณสามารถทำได้ด้วย Java เอง

Chris Campbell มีการเขียนที่ยอดเยี่ยมและมีรายละเอียดเกี่ยวกับการปรับขนาดภาพ - ดูบทความนี้บทความนี้

เชษฐ์ฮาและ Romain ผู้ชายยังมีรายละเอียดและข้อมูลมากเขียนขึ้นของการปรับภาพในหนังสือของพวกเขาลูกค้าสกปรกที่อุดมไป


7
บทความของ Chris เป็นสิ่งที่กระตุ้นให้ผมเขียน imgscalr ตั้งแต่แรก และคำถามเช่นนี้ (และคำตอบเช่นเดียวกับคุณ) ผู้คนมากมายถามซ้ำแล้วซ้ำอีกว่าจะทำอย่างไรให้ภาพขนาดย่อดูดีจากรูปภาพ มีหลายวิธีในการทำคริสไม่ใช่วิธีที่ดีที่สุดเสมอไปทั้งนี้ขึ้นอยู่กับสิ่งที่คุณพยายามทำและการลดขนาดใหญ่เพียงใด imgscalr กล่าวถึงทั้งหมดนี้และเป็น 1 คลาส
Riyad Kalla

2
+1 ฉันเห็นด้วยลูกค้า Filthy Rich เป็นหนึ่งในหนังสือ java ที่ดีที่สุดที่มีอยู่ในระดับเดียวกับ "Effective java" แต่ ImgScalr เป็นสิ่งที่ฉันใช้เพราะฉันขี้เกียจ
Shawn Vader


9

หากคุณกำลังจัดการกับภาพขนาดใหญ่หรือต้องการผลลัพธ์ที่ดูดีมันไม่ใช่เรื่องเล็กน้อยใน java เพียงแค่ทำผ่านการปรับขนาดผ่าน Graphics2D จะไม่สร้างภาพขนาดย่อที่มีคุณภาพสูง คุณสามารถทำได้โดยใช้ JAI แต่ต้องทำงานมากกว่าที่คุณจะคิดว่าจะได้อะไรที่ดูดีและ JAI มีนิสัยที่น่ารังเกียจในการทำให้ JVM ของคุณของคุณมีข้อผิดพลาด OutOfMemory

ฉันขอแนะนำให้ใช้ ImageMagick เป็นไฟล์ปฏิบัติการภายนอกหากคุณสามารถหลีกเลี่ยงได้ ใช้งานง่ายและทำงานได้ดีโดยที่คุณไม่ต้องทำ


4

หากการติดตั้ง imagemagick บน maschine เป็นตัวเลือกฉันขอแนะนำ im4java เป็นเลเยอร์นามธรรมที่บางมากบนอินเทอร์เฟซบรรทัดคำสั่ง แต่ทำงานได้ดีมาก


3

Java API ไม่มีคุณสมบัติการปรับมาตราส่วนมาตรฐานสำหรับรูปภาพและการดาวน์เกรดคุณภาพของรูปภาพ

ด้วยเหตุนี้ฉันจึงพยายามใช้ cvResize จาก JavaCV แต่ดูเหมือนว่าจะทำให้เกิดปัญหา

ฉันพบไลบรารีที่ดีสำหรับการปรับขนาดรูปภาพ: เพียงเพิ่มการอ้างอิงสำหรับ "java-image-scaling" ใน pom.xml ของคุณ

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

ในที่เก็บ maven คุณจะได้รับเวอร์ชันล่าสุดสำหรับสิ่งนี้

อดีต ในโปรแกรม java ของคุณ

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

นอกจากนี้ยังมีให้บริการบน GitHub ( github.com/mortennobel/java-image-scaling.git ) และมีเวอร์ชัน 8.7 สำหรับตอนนี้ จำเป็นต้องมีการแก้ไข li'l ใน pom.xml คุณ (การเปลี่ยนแหล่งที่มาและเป้าหมายเป็นอย่างน้อย 1.6 เนื่องจาก Maven รุ่นใหม่ไม่รองรับ 1.5 อีกต่อไป)
Cromax

2

คุณสามารถลองใช้ระบบประมวลผลภาพ GraphicsMagickกับim4javaเป็นอินเตอร์เฟส comand-line สำหรับ Java

ข้อดีของ GraphicsMagick มีมากมาย แต่สำหรับทุกคน:

  • GM ใช้ในการประมวลผลไฟล์หลายพันล้านไฟล์ในเว็บไซต์ภาพถ่ายที่ใหญ่ที่สุดในโลก (เช่น Flickr และ Etsy)

1

Image Magick ได้รับการกล่าวถึง มีโครงการส่วนหน้าของ JNI ที่เรียกว่า JMagick ไม่ใช่โครงการที่มีเสถียรภาพโดยเฉพาะอย่างยิ่ง (และ Image Magick เองก็เป็นที่ทราบกันดีว่าเปลี่ยนไปมากและยังทำลายความเข้ากันได้) กล่าวได้ว่าเรามีประสบการณ์ที่ดีในการใช้ JMagick และ Image Magick เวอร์ชันที่เข้ากันได้ในสภาพแวดล้อมการใช้งานจริงเพื่อทำการปรับขนาดด้วยอัตราความเร็วที่สูงและมีความหน่วงแฝงต่ำ ความเร็วนั้นดีขึ้นอย่างมากด้วยไลบรารีกราฟิก Java ทั้งหมดที่เราเคยลองก่อนหน้านี้

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


1

เพียงใช้คำตอบของ Burkhard แต่เพิ่มบรรทัดนี้หลังจากสร้างกราฟิก:

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

คุณยังสามารถตั้งค่าเป็น BICUBIC ซึ่งจะให้ภาพที่มีคุณภาพดีขึ้น แต่เป็นการดำเนินการที่มีราคาแพงกว่า มีคำแนะนำการเรนเดอร์อื่น ๆ ที่คุณสามารถตั้งค่าได้ แต่ฉันพบว่าการแก้ไขทำให้เกิดเอฟเฟกต์ที่โดดเด่นที่สุด โปรดทราบว่าหากคุณต้องการซูมเข้ามาก ๆ โค้ด java มักจะช้ามาก ฉันพบว่าภาพขนาดใหญ่เริ่มสร้างความล่าช้าในการซูมประมาณ 300% แม้ว่าจะมีการตั้งค่าคำแนะนำการแสดงผลทั้งหมดเพื่อปรับให้เหมาะสมกับความเร็วมากกว่าคุณภาพก็ตาม



1

ปรากฎว่าการเขียนสเกลเลอร์นักแสดงไม่ใช่เรื่องเล็กน้อย ฉันทำครั้งเดียวสำหรับโครงการโอเพ่นซอร์ส: ImageScaler ImageScaler

โดยหลักการแล้ว 'java.awt.Image # getScaledInstance (int, int, int)' จะทำงานได้เช่นกัน แต่มีข้อบกพร่องที่น่ารังเกียจกับสิ่งนี้ - ดูรายละเอียดในลิงค์ของฉัน


0

ฉันได้พัฒนาโซลูชันด้วยคลาสที่มีให้ใช้งานฟรี (AnimatedGifEncoder, GifDecoder และ LWZEncoder) สำหรับจัดการภาพเคลื่อนไหว GIF
คุณสามารถดาวน์โหลด jgifcode jar และรันคลาส GifImageUtil ลิงค์: http://www.jgifcode.com


1
โปรดระบุในคำตอบหากคุณมีส่วนเกี่ยวข้องกับผลิตภัณฑ์ที่คุณแนะนำ
Hans Olsson

ว้าว ... สำหรับการปรับขนาดภาพเคลื่อนไหว GIF หรือไม่? และฟรี ?? ว้าวววววววววววววว ...
gumuruh

ใช่สิ่งนี้พัฒนาโดยฉัน นี่คือซอร์สโค้ดของมันgithub.com/rt29/jgifcode - ตอนนี้อยู่ที่นี่ ฉันไม่สนับสนุนมันอีกต่อไป
Rohit Tiwari


0

หากคุณไม่ต้องการนำเข้าimgScalrเช่น @Riyad Kalla คำตอบข้างต้นที่ฉันทดสอบก็ใช้ได้ดีคุณสามารถทำได้จากคำตอบของ Peter Walser @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

ลองใช้วิธีการต่อไปนี้:

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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.