全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

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

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


# java  # ImageIO.writer  # 使用BufferedImage生成jpeg图像  # 生成jpeg  # 一文带你掌握Java ImageIO类  # 解决idea启动报错javax.imageio.IIOException的问题  # JAVA ImageIO.read方法报错/无效问题及解决  # 抛出  # 都是  # 是有  # 但在  # 网上  # 这一  # 也有  # 才是  # 都能  # 找不到  # 都没  # 是怎么  # 其他的  # 是从  # 有一定  # 就没  # 希望能  # 互联  # 只在  # 来做 


相关文章: TestNG的testng.xml配置文件怎么写  如何做静态网页,sublimetext3.0制作静态网页?  青岛网站建设如何选择本地服务器?  在线制作视频网站免费,都有哪些好的动漫网站?  建站之星代理平台如何选择最佳方案?  东莞专业制作网站的公司,东莞大学生网的网址是什么?  简单实现Android文件上传  如何在西部数码注册域名并快速搭建网站?  做企业网站制作流程,企业网站制作基本流程有哪些?  ,交易猫的商品怎么发布到网站上去?  建站之星安装模板失败:服务器环境不兼容?  如何用PHP快速搭建CMS系统?  北京专业网站制作设计师招聘,北京白云观官方网站?  如何快速搭建高效WAP手机网站?  网站代码制作软件有哪些,如何生成自己网站的代码?  如何在腾讯云服务器上快速搭建个人网站?  建站之星如何修改网站生成路径?  如何构建满足综合性能需求的优质建站方案?  重庆市网站制作公司,重庆招聘网站哪个好?  如何用IIS7快速搭建并优化网站站点?  学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?  微信小程序 五星评分(包括半颗星评分)实例代码  香港服务器建站指南:外贸独立站搭建与跨境电商配置流程  如何快速打造个性化非模板自助建站?  建站主机选购指南与交易推荐:核心配置解析  宠物网站制作html代码,有没有专门介绍宠物如何养的网站啊?  已有域名和空间,如何快速搭建网站?  开心动漫网站制作软件下载,十分开心动画为何停播?  如何获取开源自助建站系统免费下载链接?  如何在阿里云香港服务器快速搭建网站?  郑州企业网站制作公司,郑州招聘网站有哪些?  如何在Windows虚拟主机上快速搭建网站?  c# Task.Yield 的作用是什么 它和Task.Delay(1)有区别吗  建站之星如何实现五合一智能建站与营销推广?  c++怎么编写动态链接库dll_c++ __declspec(dllexport)导出与调用【方法】  杭州银行网站设计制作流程,杭州银行怎么开通认证方式?  如何通过老薛主机一键快速建站?  用v-html解决Vue.js渲染中html标签不被解析的问题  高防服务器租用如何选择配置与防御等级?  如何通过PHP快速构建高效问答网站功能?  php能控制zigbee模块吗_php通过串口与cc2530 zigbee通信【介绍】  如何在万网自助建站中设置域名及备案?  在线制作视频的网站有哪些,电脑如何制作视频短片?  详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)  深圳网站制作费用多少钱,读秀,深圳文献港这样的网站很多只提供网上试读,但有些人只要提供试读的文章就能全篇下载,这个是怎么弄的?  建站之星免费模板:自助建站系统与智能响应式一键生成  英语简历制作免费网站推荐,如何将简历翻译成英文?  如何确认建站备案号应放置的具体位置?  如何在Mac上搭建Golang开发环境_使用Homebrew安装和管理Go版本  制作门户网站的参考文献在哪,小说网站怎么建立? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。