java转webp

java转换图片格式,生成webp图片文件

公司最近的新项目,有移动端,所以需要对普通图片进行压缩,减少图片的大小。这样既能较少用户耗费的流量,又能提高用户浏览速度,而且图片质量基本上和压缩前保持不变,有利于提升用户体验。

  • webp简介
  • webp环境配置
  • webp转换工具类
  • 可能出现的异常
  • 图片上传controller demo
  • jar包上传到nexus私服

webp简介
  • WebP是谷歌的图片格式,java 类库imageio 是不支持此种格式的。目前除了在线转换以及工具以外,第三方类库转webp格式大致有:
  • linux:Google libwebp 既是类库也可以在命令行调用
  • Python:Python Image Library(PIL)及其分支 https://pypi.python.org/pypi/PIL 不太了解
  • Java:luciad/webp-imageio https://bitbucket.org/luciad/webp-imageio/src windows / linux亲测可用

webp环境配置
  • 本例使用的webp的环境
    • Windows 10 专业版,Windows 7 x86 ,Windows 7 x64
    • Linux server244 3.10.0-514.21.1.el7.x86_64 #1 SMP Thu May 25 17:04:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
  • 环境配置所需资源下载:webp开发工具包(java)
  • 这里使用的webp-imageio这个包,需要根据操作系统和jdk位数,来编译一些环境配置文件(通常使用cmake编译,这个我不是很懂),但是我怀疑最终是通过修改native方法来实现的。
  • 配置环境:将对应的dll或者os文件,放到安装的jdk的bin下面(java.library.path下),比如我的电脑里如下图:
  • 注意:.dll文件是windows用的,.os文件是linux的。当然,资源包里还准备的有macos的

这里写图片描述

  • linux下:建议写一个Test.java,然后敲命令javac Test编译,再敲命令java Test运行编译后的文件,就能输出当前系统下的java.library.path
public class Test{

    public static void main(String[] args) {
        String a = System.getProperty("java.library.path");
        System.out.println(a);
    }
}
例如我的是:/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
然后把对应的.os文件放在/usr/java/packages/lib/amd64里面(没有这个文件夹就自己新建个)

webp工具类
  • 配好环境后,应该就可以直接跑工具类的main方法了
import javax.imageio.ImageIO;

import java.awt.image.BufferedImage;
import java.io.*;

import java.net.URL;

/**
 * Description: 普通格式图片转换为webp格式图片 工具类
 *  耗时稍长,建议异步调用
 *
 * @author XU SAN DUO
 * Date: 2018/1/11 15:13
 * @version 1.0
 */
public class ImageToWebpUtil {

    public static final String WEBP = "webp";
    public static final String WEBP_SUFFIX = ".webp";

    /**
     * 1. 传入图片文件路径,返回file对象
     * @param imgFilePath 图片文件路径(比如转换图片为F:/1.png 那么转换后的webp文件为:F:/1.png.webp)
     * @return
     */
    public static File toWebpFile(String imgFilePath){
        File imgFile = new File(imgFilePath);
        File webpFile = new File(imgFilePath + WEBP_SUFFIX);
        try {
            BufferedImage bufferedImage = ImageIO.read(imgFile);
            ImageIO.write(bufferedImage, WEBP, webpFile);
        }catch (Exception e){
            e.printStackTrace();
        }
        return webpFile;
    }

    /**
     * 2. 传入图片url,返回file对象
     * @param imgUrlPath 图片路径url
     * @param webpFilePath 生成的webp文件路径
     * @return
     */
    public static File toWebpFile(String imgUrlPath, String webpFilePath){
        File webpFile = new File(webpFilePath);
        try {
            BufferedImage bufferedImage = ImageIO.read(new URL(imgUrlPath));
            ImageIO.write(bufferedImage, WEBP, webpFile);
        }catch (Exception e){
            e.printStackTrace();
        }
        return webpFile;
    }

    /**
     * 3. 传入图片文件路径,返回InputStream
     * @param imgFilePath 图片文件路径(比如转换图片为F:/1.png 那么转换后的webp文件为:F:/1.png.webp)
     * @return
     */
    public static InputStream toWebpStream(String imgFilePath){
        File imgFile = new File(imgFilePath);
        File webpFile = new File(imgFilePath + WEBP_SUFFIX);
        FileInputStream fis = null;
        try {
            BufferedImage bufferedImage = ImageIO.read(imgFile);
            ImageIO.write(bufferedImage, WEBP, webpFile);
            fis = new FileInputStream(webpFile);
        }catch (Exception e){
            e.printStackTrace();
        } finally {
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return fis;
    }

    /**
     * 4. 传入图片url,返回InputStream
     * @param imgUrlPath 图片路径url
     * @param webpFilePath 生成的webp文件路径
     * @return
     */
    public static InputStream toWebpStream(String imgUrlPath, String webpFilePath){
        File webpFile = new File(webpFilePath);
        FileInputStream fis = null;
        try {
            BufferedImage bufferedImage = ImageIO.read(new URL(imgUrlPath));
            ImageIO.write(bufferedImage, WEBP, webpFile);
            fis = new FileInputStream(webpFile);
        }catch (Exception e){
            e.printStackTrace();
        } finally {
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return fis;
    }

    // 测试
    public static void main(String[] args) {
        long start = System.currentTimeMillis();


        // 1. test 传入图片文件路径,返回file对象
//        String imgFilePath = "F:/test.png";
//        File result = toWebpFile(imgFilePath);

        // 2. test 传入图片url,返回file对象
        String imgUrlPath = "http://pic151.nipic.com/file/20171228/22164794_210348306033_2.jpg";
        String webpFilePath = "F:/xiche.jpg.webp";
        File result = toWebpFile(imgUrlPath,webpFilePath);

        // 3. test 传入图片文件路径,返回InputStream
//        String imgFilePath = "F:/test.png";
//        InputStream result = toWebpStream(imgFilePath);

        // 4. test 传入图片url,返回InputStream
//        String imgUrlPath = "http://pic151.nipic.com/file/20171228/22164794_210348306033_2.jpg";
//        String webpFilePath = "F:/xiche.jpg.webp";
//        InputStream result = toWebpStream(imgUrlPath,webpFilePath);


        long end = System.currentTimeMillis();
        System.out.println("用时:"+(end - start) + "  ms ; return ---->");
        System.out.print(result);
    }

}

可能出现的异常
  • java.lang.UnsatisfiedLinkError: no webp-imageio in java.library.path,说明环境没有配置好,解决办法:请重新仔细看一下上面说的环境配置
  • java.lang.NoClassDefFoundError: Could not initialize class com.luciad.imageio.webp.WebPWriteParam,虽然把对应的配置文件放在指定位置,但是是在应用程序启动之后放进去的,解决办法:重启你的application

图片上传controller demo
  • 这只是一个简易示例。(用的阿里的oss)
/**
 *
 * 文件上传
 * @param file 图片对象
 * @param fileUrl 要存放的ossKey
 * return
 */
@ApiOperation(value = "上传图片", httpMethod = "POST", notes = "上传图片")
@RequestMapping(value = "/uploadImg", method = RequestMethod.POST)
@ResponseBody
public ResultVO<Object> uploadImg(MultipartFile file, String fileUrl) {

    ResultVO<Object> result = new ResultVO<>();
    String logoUrlFileUrl = "";
    try {
        if (!file.isEmpty()) {
            logoUrlFileUrl += OSSFileOptUtils.uploadFile3(file, fileUrl, evnType);
            result.setData(logoUrlFileUrl);
            result.setStatus(ResultStatusEnum.OK.getValue());
            result.setMessage("上传图片成功");

            final String imgUrl = OssConstant.img_url_prefix + logoUrlFileUrl;
            final String webpKey = logoUrlFileUrl.substring(1) + ImageToWebpUtil.WEBP_SUFFIX;
            final String webpFilePath = this.webpFolder + file.getOriginalFilename() 
                + ImageToWebpUtil.WEBP_SUFFIX;
            new Thread(new Runnable(){
                @Override
                public void run() {
                    File webp = ImageToWebpUtil.toWebpFile(imgUrl,webpFilePath);
                    OSSFileOptUtils.uploadFile(OssConstant.shanghai_bucket_name,webpKey,webp,1);
                    log.info("【已上传webp文件:"+webpKey+"】");
                }
            }).start();
        }
    } catch (Exception e) {
        e.printStackTrace();
        result.setStatus(ResultStatusEnum.ERROR.getValue());
        result.setMessage("上传图片失败!");
        log.error("上传失败", e);
    }
    return result;
}

jar包上传到nexus私服
  • 这个webp的作者目前还没有把它上传到maven repository,而我们实际开发中,公司里一般都有自己搭建的nexus私服。所以这里就再啰嗦一点,写一下如何上传webp.jar到nexus私服
  • 仅介绍命令行上传

    • 安装nexus私服,略。但是要记住 ++id++ 和 ++url++

      <distributionManagement>
          <repository>
              <id>nexus-releases</id>
              <url>http://192.168.0.240:8081/repository/maven-releases/</url>
          </repository>
          <snapshotRepository>
              <id>nexus-snapshots</id>
              <url>http://192.168.0.240:8081/repository/maven-snapshots/</url>
          </snapshotRepository>
      </distributionManagement>
    • 假如现在有一个java项目,配置了maven。那么,需要在项目所依赖的maven的setting.xml中添加对这个nexus的配置:id,username,password一定要正确

      <server> 
          <id>nexus-releases</id> 
          <username>admin</username> 
          <password>admin123</password> 
      </server>
      <server> 
          <id>nexus-snapshots</id> 
          <username>admin</username> 
          <password>admin123</password> 
      </server>
    • 进入到项目根目录下,执行命令:(参数应该一看就懂)

    • 为什么要到项目根目录下执行:因为项目引用了setting.xml,而里面配置了username和password。这样就相当于有了权限
      mvn deploy:deploy-file -DgroupId=com.luciad.imageio -DartifactId=webp -Dversion=0.4.2 -Dpackaging=jar -Dfile=E:/a/webp-imageio-0.4.2.jar -Durl=http://192.168.0.240:8081/repository/maven-releases/ -DrepositoryId=nexus-releases
### Java 实现图片 WebP 格式的解决方案 由于标准的 `javax.imageio.ImageIO` 并未提供对 WebP 格式的支持[^1],因此需要借助第三方库来完成此功能。以下是两种常见的方法: #### 方法一:使用 Google 的 Guetzli 和 WebP 库 Google 提供了一个名为 `libwebp` 的开源项目,该项目包含了用于编码和解码 WebP 文件的功能。可以通过 JNI 调用该库或者直接利用其封装好的 Java API。 ##### 示例代码 (基于 libwebp-java 封装) ```java import com.google.webp.WebpCodec; import java.awt.image.BufferedImage; import javax.imageio.ImageIO; public class ImageToWebPConverter { public static void main(String[] args) throws Exception { BufferedImage image = ImageIO.read(new java.io.File("input.jpg")); byte[] webpData = WebpCodec.encode(image, 0.8f); // 压缩质量设置为 80% try (java.io.OutputStream out = new java.io.FileOutputStream("output.webp")) { out.write(webpData); } } } ``` 上述代码通过 `com.google.webp.WebpCodec` 完成了图像到 WebP 格式的转换操作。 --- #### 方法二:调用 FFmpeg 工具进行格式转换 如果不想依赖于特定平台上的本地库,则可以考虑使用命令行工具 FFmpeg 来执行文件格式转换。FFmpeg 支持多种多媒体格式之间的相互转换,包括静态图片WebP 动图/静图的操作。 ##### 示例代码 (Java 中调用 FFmpeg 进行图片转换) ```java import java.io.BufferedReader; import java.io.InputStreamReader; public class FfmpegImageConverter { public static void convertToWebP(String inputPath, String outputPath) throws Exception { ProcessBuilder pb = new ProcessBuilder( "C:\\software\\ffmpeg\\bin\\ffmpeg", "-i", inputPath, "-c:v", "libwebp", "-lossless", "0", "-qscale", "75", "-preset", "default", "-an", "-vsync", "vfr", outputPath); Process process = pb.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } int exitCode = process.waitFor(); if (exitCode == 0) { System.out.println("Conversion successful!"); } else { throw new RuntimeException("Failed to convert the file."); } } public static void main(String[] args) throws Exception { convertToWebP("input.png", "output.webp"); } } ``` 这段程序展示了如何在 Windows 系统下显式指定 FFmpeg 可执行文件路径并运行相应的参数组合以生成目标 WebP 文件[^3]。 注意,在 Linux 上只需简单替换 `"C:\\software\\ffmpeg\\bin\\ffmpeg"` 部分为 `"ffmpeg"` 即可正常工作。 --- ### 总结 以上提供了两种主流方式实现 Java 下的图片WebP 格式的化过程。对于轻量级需求推荐采用第一种方案;而对于复杂场景比如批量处理或是涉及动态 GIF 则更适合第二种途径。
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值