详解java使用ImageIO.writer从BufferedImage生成jpeg图像遇到问题总结及解决
这篇文章主要介绍了java 使用ImageIO.writer从BufferedImage生成jpeg图像遇到问题总结及解决的相关资料,需要的朋友可以参考下
java 使用ImageIO.writer从BufferedImage生成jpeg图像遇到问题总结及解决
生成jpeg图像这是个非常非常简单的东西了,网上很多介绍是直接用com.sun.image.codec.jpeg.JPEGImageEncoder来实现,如下:
/** * 将原图压缩生成jpeg格式的数据 * @param source * @return */ public static byte[] wirteJPEGBytes(BufferedImage source){ if(null==source) throw new NullPointerException(); ByteArrayOutputStream output = new ByteArrayOutputStream(); JPEGImageEncoder jencoder = JPEGCodec.createJPEGEncoder(output); JPEGEncodeParam param = jencoder.getDefaultJPEGEncodeParam(source); param.setQuality(0.75f, true); jencoder.setJPEGEncodeParam(param); try { jencoder.encode(source); } catch (ImageFormatException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } return output.toByteArray(); }
JPEGImageEncoder只是sun的jpeg编码实现,并不是标准的Java API,只在sun jvm中被支持,但在其他的jvm上,并不会被支持。
而且,虽然上面的代码在Java 1.6,1.7上都能正常执行,但在如果使用java 1.8,上面这个代码会报错:
访问限制:由于对必需的库 C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar 具有一定限制,因此无法访问类型JPEGImageEncoder
所以这个方法是有局限性的。
走捷径是不行的,还是得规规矩矩按java的规范来做,ImageIO类中提供了ImageIO.writer方法可以生成指定的格式的图像,才是正规的实现方式。
但是使用ImageIO.writer方法也是有讲究的。
我原先是这样写的,就是简单的调用ImageIO.writer方法生成jpeg数据:
/** * 将原图压缩生成jpeg格式的数据 * @param source * @return * @see #wirteBytes(BufferedImage, String) */ public static byte[] wirteJPEGBytes(BufferedImage source){ return wirteBytes(source,"JPEG"); } /** * 将原图压缩生成jpeg格式的数据 * @param source * @return * @see #wirteBytes(BufferedImage, String) */ public static byte[] wirteJPEGBytes(BufferedImage source){ return wirteBytes(source,"JPEG"); } /** * 将{@link BufferedImage}生成formatName指定格式的图像数据 * @param source * @param formatName 图像格式名,图像格式名错误则抛出异常 * @return */ public static byte[] wirteBytes(BufferedImage source,String formatName){ Assert.notNull(source, "source"); Assert.notEmpty(formatName, "formatName"); ByteArrayOutputStream output = new ByteArrayOutputStream(); try { if(!ImageIO.write(source, formatName.toLowerCase(), output)) // 返回false则抛出异常 throw new IllegalArgumentException(String.format("not found writer for '%s'",formatName)); } catch (IOException e) { throw new RuntimeException(e); } return output.toByteArray(); }
处理了几万张图像文件都没问题,遇到一张png图像,ImageIO.write居然返回false,抛出异常了。
究其原因,是ImageIO.wite方法在中调用的私有方法getWriter寻找合适的ImageWriter时不仅与formatName相关,还是输入的原图有关(具体是怎么相关的,因为逻辑关系太复杂没有深究),造成getWriter方法找不到对应的ImageWriter。
参考网上别人的写法改成这样就没问题了:
/** * 将{@link BufferedImage}生成formatName指定格式的图像数据 * @param source * @param formatName 图像格式名,图像格式名错误则抛出异常 * @return */ public static byte[] wirteBytes(BufferedImage source,String formatName){ Assert.notNull(source, "source"); Assert.notEmpty(formatName, "formatName"); ByteArrayOutputStream output = new ByteArrayOutputStream(); BufferedImage newBufferedImage = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g = newBufferedImage.createGraphics(); try { g.drawImage(source, 0, 0,null); if(!ImageIO.write(newBufferedImage, formatName, output)) throw new IllegalArgumentException(String.format("not found writer for '%s'",formatName)); } catch (IOException e) { throw new RuntimeException(e); }finally{ g.dispose(); } return output.toByteArray(); }
基本的思路就是重创建一个大小相同的BufferedImage,然后用Graphics.drawImage方法将原图写入新的BufferedImage对象,通过这一道转换,抹平了,不同类型图像格式生成的BufferedImage对象之间的区别,再调用 ImageIO.write 对新的ImageIO.write对象进行图像处理就不会有问题了。
改进
在我的项目中图像数据是从互联网上搜索到的,遇到的图像格式绝大部分都是jpeg,但也有少量的png,bmp等格式,对于占绝大多数的jpeg图像来说,我最开始的方法都是有效的,而上面的这个方法多出一道工序就显得有些多余,还浪费资源,所以又改进了上述的方法,基本的原理就是先尝试直接ImageIO.write来生成jpeg,如果失败,就用第二种方式。
/** * 将{@link BufferedImage}生成formatName指定格式的图像数据 * @param source * @param formatName 图像格式名,图像格式名错误则抛出异常 * @return */ public static byte[] wirteBytes(BufferedImage source,String formatName){ Assert.notNull(source, "source"); Assert.notEmpty(formatName, "formatName"); ByteArrayOutputStream output = new ByteArrayOutputStream(); Graphics2D g = null; try { for(BufferedImage s=source;!ImageIO.write(s, formatName, output);){ if(null!=g) throw new IllegalArgumentException(String.format("not found writer for '%s'",formatName)); s = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_INT_RGB); g = s.createGraphics(); g.drawImage(source, 0, 0,null); } } catch (IOException e) { throw new RuntimeException(e); } finally { if (null != g) g.dispose(); } return output.toByteArray(); }
Atas ialah kandungan terperinci 详解java使用ImageIO.writer从BufferedImage生成jpeg图像遇到问题总结及解决. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Panduan untuk Square Root di Java. Di sini kita membincangkan cara Square Root berfungsi di Java dengan contoh dan pelaksanaan kodnya masing-masing.

Panduan Nombor Sempurna di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor Perfect dalam Java?, contoh dengan pelaksanaan kod.

Panduan untuk Penjana Nombor Rawak di Jawa. Di sini kita membincangkan Fungsi dalam Java dengan contoh dan dua Penjana berbeza dengan contoh lain.

Panduan untuk Nombor Armstrong di Jawa. Di sini kita membincangkan pengenalan kepada nombor Armstrong di java bersama-sama dengan beberapa kod.

Panduan untuk Weka di Jawa. Di sini kita membincangkan Pengenalan, cara menggunakan weka java, jenis platform, dan kelebihan dengan contoh.

Panduan untuk Nombor Smith di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor smith di Jawa? contoh dengan pelaksanaan kod.

Dalam artikel ini, kami telah menyimpan Soalan Temuduga Spring Java yang paling banyak ditanya dengan jawapan terperinci mereka. Supaya anda boleh memecahkan temuduga.

Java 8 memperkenalkan API Stream, menyediakan cara yang kuat dan ekspresif untuk memproses koleksi data. Walau bagaimanapun, soalan biasa apabila menggunakan aliran adalah: bagaimana untuk memecahkan atau kembali dari operasi foreach? Gelung tradisional membolehkan gangguan awal atau pulangan, tetapi kaedah Foreach Stream tidak menyokong secara langsung kaedah ini. Artikel ini akan menerangkan sebab -sebab dan meneroka kaedah alternatif untuk melaksanakan penamatan pramatang dalam sistem pemprosesan aliran. Bacaan Lanjut: Penambahbaikan API Java Stream Memahami aliran aliran Kaedah Foreach adalah operasi terminal yang melakukan satu operasi pada setiap elemen dalam aliran. Niat reka bentuknya adalah
