java服务器端图片转换webp以及批量转换webp脚本

来源:互联网 发布:mac基于linux还是unix 编辑:程序博客网 时间:2024/05/17 22:55

一直在负责实验室后台新功能的开发和维护,最近有了一个新需求:给实验室官网添加webp格式的支持.

具体的就是说首先所有上传图片的操作需要在上传后转换出一份webp格式的.

准备工作

其实将图片转换为webp并不难,只需要调用google提供的转换器即可.转换器可以从这里下载.

转换器bin目录中包括以下工具
- cwebp:将图片转换为webp格式
- dwebp:解码webp
- gif2webp:gif动图转换为webp格式

一般这要这样就可以转换好了cwebp [options] input_file -o output_file.webp.

如果是gif就将工具换为gif2webp 其他都不用改.常用option为-q 设置压缩质量 如75质量等.

更多的使用方式可以去百度查找

思路及实现

使用java调用转换器

这里有一份对转换过程的封装

public class ImageFormatConverter {    // private static Logger log = Logger.getLogger(ImageFormatConverter.class);    public static boolean convertToWebp(String inputFile, String outputFile) {        return convertToWebp(inputFile, outputFile, 75);    }    public static boolean convertToWebp(String inputFile, String outputFile, Integer quality) {        if (!new File(inputFile).exists()) {            return false;        }        String outputPath = FilenameUtils.getFullPath(outputFile);        if (!new File(outputPath).exists()) {            new File(outputPath).mkdirs();        }        return executeCWebp(inputFile, outputFile, quality);    }    /**     * execute cwebp command:cwebp [options] input_file -o output_file.webp     */    private static boolean executeCWebp(String inputFile, String outputFile, Integer quality) {        boolean result = false;        ClassLoader cl = ImageFormatConverter.class.getClassLoader(); // get classloader        // init cwebp path,and set privilege of 755.        // you can replace cwebpath in your case. in this case, we used a macos-based cwebp        String cwebpPath = cl.getResource("libwebp/cwebp_macos").getPath();        try {            String chmodCommand = "chmod 755 " + cwebpPath;            Runtime.getRuntime().exec(chmodCommand).waitFor();            StringBuilder command = new StringBuilder(cwebpPath);            command.append(" -q " + (quality == 0 ? 75 : quality));            command.append(" " + inputFile);            command.append(" -o " + outputFile);            Runtime.getRuntime().exec(command.toString());            result = true;        } catch (Exception e) {            // log.error("An error happend when convert to webp. Img is: " + inputFile, e);        }        return result;    }    public static void main(String[] args) {        String inputFile = "/Users/wangjieyu/Downloads/libwebp-0.5.0-rc1-mac-10.9/input/logo.png";        String outputFile = "/Users/wangjieyu/Downloads/libwebp-0.5.0-rc1-mac-10.9/output/logo.webp";        if (executeCWebp(inputFile, outputFile, 90)) {            System.out.println("convert ok~");        } else {            System.out.println("sth wrong happened");        }    }}

感谢Flyne的代码

然后因为我的需求是将上传图片转换为webp格式保存在同目录,因此我简化了参数,在covertToWebp方法中生成outputFile参数,代码如下:

public static boolean convertToWebp(String inputFile) {String outputFile = inputFile.split("\\.")[0] + ".webp";return convertToWebp(inputFile, outputFile, 75);}

此时只需要将对该方法的调用放到所有上传图片的方法中就可以了

批量转换脚本

先上代码

import java.io.*;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.HashSet;import java.util.Set;public class Converter {private static String driver = "com.mysql.jdbc.Driver";private static String dbname = "";private static String password = "";private static String username = "root";private static String url = "jdbc:mysql://localhost:3306/" + dbname;private static String sql = "SELECT img AS filename FROM activity UNION SELECT img AS filename FROM app "+ "UNION SELECT portrait AS filename FROM member UNION SELECT mien_img AS filename FROM member "+ "UNION SELECT graduate_img AS filename FROM member UNION SELECT portrait AS filename FROM member_graduate "+ "UNION SELECT mien_img AS filename FROM member_graduate UNION SELECT graduate_img AS filename FROM member_graduate "+ "UNION SELECT url AS filename FROM res UNION SELECT img AS filename FROM wiki;";private static String sql1 = "SELECT content_md AS content FROM wiki UNION SELECT content AS content FROM activity ;";private static int delNum = 0;private static String content = "";private static boolean needDel = false;private static Set<String> set = new HashSet<>();public static void main(String[] args) {if (args.length == 0) {System.out.println("无参数");return;}if (args.length > 1) {String argc = args[1];if (argc.equals("y")) {needDel = true;content = getString();set = getFileSet();}}File file = new File(args[0]);//File file= new File("/mnt/c/linux/webp");delAndCovert(file);System.out.println(delNum);}public static void delAndCovert(File file) {File[] filelist = file.listFiles();for (File file2 : filelist) {if (file2.isDirectory()) {delAndCovert(file2);} else {System.out.print(file2.getName() + " ");if (!(file2.getName().toUpperCase().endsWith("JPG") || file2.getName().toUpperCase().endsWith("JPEG")|| file2.getName().toUpperCase().endsWith("PNG")|| file2.getName().toUpperCase().endsWith("GIF")|| file2.getName().toUpperCase().endsWith("WEBP"))) {System.out.println("don 't touch me!");continue;}if (needDel == false) {System.out.println(file2.getPath());convertToWebp(file2.getPath());} else {if (set.contains(file2.getName()) || content.contains(file2.getName())) {System.out.println("yes! " + file2.getPath());convertToWebp(file2.getPath());} else {System.out.print("no ");if (file2.delete())System.out.println("delete");elseSystem.out.println("error");delNum++;}}}}}public static String getString() {Connection connection = getConn();PreparedStatement preparedStatement = null;StringBuilder s = new StringBuilder();ResultSet resultSet = null;try {preparedStatement = connection.prepareStatement(sql1);resultSet = preparedStatement.executeQuery();while (resultSet.next()) {s.append(resultSet.getString(1));}try {if (resultSet != null) {resultSet.close();}if (preparedStatement != null)preparedStatement.close();if (connection != null)connection.close();} catch (SQLException e) {e.printStackTrace();}} catch (Exception e) {//TODO: handle exception}return s.toString();}public static Set<String> getFileSet() {Connection connection = getConn();PreparedStatement preparedStatement = null;ResultSet resultSet = null;Set<String> list = new HashSet<>();String filename;try {preparedStatement = connection.prepareStatement(sql);resultSet = preparedStatement.executeQuery();while (resultSet.next()) {filename = resultSet.getString(1);filename = filename.substring(filename.lastIndexOf("/") + 1);list.add(filename);}try {if (resultSet != null) {resultSet.close();}if (preparedStatement != null)preparedStatement.close();if (connection != null)connection.close();} catch (SQLException e) {e.printStackTrace();}} catch (Exception e) {e.printStackTrace();}return list;}public static Connection getConn() {Connection connection = null;try {Class.forName(driver);connection = DriverManager.getConnection(url, username, password);} catch (Exception e) {e.printStackTrace();}return connection;}public static boolean convertToWebp(String inputFile) {String outputFile = inputFile.split("\\.")[0] + ".webp";return convertToWebp(inputFile, outputFile, 75);}public static boolean convertToWebp(String inputFile, String outputFile, Integer quality) {if (!new File(inputFile).exists()) {return false;}return executeCWebp(inputFile, outputFile, quality);}/*** execute cwebp command:cwebp [options] input_file -o output_file.webp*/private static boolean executeCWebp(String inputFile, String outputFile, Integer quality) {boolean result = false;ClassLoader cl = Converter.class.getClassLoader();String cwebpPath = "/home/xiyoumobile/libwebp-0.4.1-linux-x86-64/bin/cwebp";if (inputFile.endsWith(".gif"))cwebpPath = "/home/xiyoumobile/libwebp-0.4.1-linux-x86-64/bin/gif2webp";//String cwebpPath = "";try {String chmodCommand = "chmod 755 " + cwebpPath;Runtime.getRuntime().exec(chmodCommand).waitFor();StringBuilder command = new StringBuilder(cwebpPath);command.append(" -q " + (quality == 0 ? 75 : quality));command.append(" " + inputFile);command.append(" -o " + outputFile);Runtime.getRuntime().exec(command.toString());result = true;} catch (Exception e) {e.printStackTrace();}return result;}}

由于开始的需求是将目录中的所有已经无用的图片删除,并将还在使用中的图片转换出webp格式,因此可以在代码中看到sql操作,

首先从数据库中检索出所有还在使用的图片文件path 分割字符串的到文件名,添加到set中,使用set是因为集合不会重复,而且检查是否包含时效率较高.通过遍历目录下文件并判断是否引用于数据库中就可知是否还有价值,对于没有价值的图片进行删除,对于有价值的进行转换.

开始写时没有考虑到网站wiki和新闻正文中的图片,所以还不小心让新闻和wiki图片都没有了 还好事先做了备份.

检测是否是新闻或wiki中的图片方法十分暴力 直接将所有新闻wiki内容得到后拼接为超大字符串,遍历文件时检测超大字符串是否contains该文件文件名就好了.

其实还可以通过遍历一遍所有新闻和wiki获得所有的文件名获得更好的时间复杂度,但是由于比较麻烦并且这只是一个脚本所以就没有继续优化.

在拼接字符串时使用了StringBuilder,因为string是不可变对象,在这种情况下会大量占用内存,而并不需要多线程就选用了效率更好的stringBuilder而不是stringBuffer

更进一步的完善

之前的代码转换目录都是代码中写死的,后来又需要去转换另外一个目录,并且和数据库没有关系,因此添加了命令行参数,第一个参数选择转换目录,第二个可选,选择是否和数据库相关和需要删除数据库没有用的图片.并将数据库检测操作和删除操作作为可选.

最后强烈推荐win10带的linux子系统wsl

原创粉丝点击