Java+ImageMagic解决UC浏览器保存的GIF无法再次打开问题

Java+ImageMagic解决UC浏览器保存的GIF无法再次打开问题

使用UC保存的gif动态图,经常就无法再次打开了。

原因:UC保存的图片可能是webp的格式,而很多图片浏览器不支持webp格式。

webp的详细介绍参考百度百科,简单理解一下就是一个压缩率很高的图片压缩格式。

我们使用Java + ImageMagic的方式将webp格式的gif文件重新转换一次,生成标准的gif后就支持打开了。

本文简单粗暴的对所有的gif都进行了转换。有需要的小伙伴请修改handleFile方法,对输入文件进行判断。比如分析文件的头信息,来判断是否需要转换。

具体代码

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.channels.FileChannel;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 将webp格式的动态图转换为GIF
 * <p>
 * 准备参数:
 *     <ul>
 *         <li>inputFolderPath,输入目录</li>
 *         <li>outputFolderPath,输出目录</li>
 *         <li>convertFilePath,ImageMagic的Convert命令</li>
 *     </ul>
 * </p>
 *
 * @auth 羊肉馅大包子
 */
public class Webp2Gif {

    /**
     * 输入目录
     */
    private static final String inputFolderPath = "D:\\delete\\before";

    /**
     * 输出目录
     */
    private static final String outputFolderPath = "D:\\delete\\after";

    /**
     * 转换命令路径,要指向可以执行的文件。windows下一般后缀为exe
     */
    private static final String convertFilePath = "D:\\server\\ImageMagick-7.0.10-Q16\\convert.exe";

    /**
     * 是否强制覆盖
     * true:不管输出文件是否存在,都转换并覆盖
     * false:输出文件存在时不处理
     */
    private static final boolean forceOverride = true;

    public static void main(String[] args) {
        printInfo();
        doCheck();

        try {
            scan();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void printInfo() {
        System.out.println("###################################");
        System.out.println("Power by 羊肉馅大包子");
        System.out.println("Update at 2021-02-22");
        System.out.println("注意:执行过程中尽量不要修改输入目录");
        System.out.println("###################################");
    }

    private static void scan() throws IOException {
        System.out.println("开始处理");

        File inputFile = new File(inputFolderPath);

        Path path = inputFile.toPath();
        int inputNameCount = path.getNameCount();

        File outFolder = new File(outputFolderPath);

        Files.walkFileTree(path, new FileVisitor<>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {

                if (!dir.equals(path)) {
                    File outFile = new File(outFolder, dir.subpath(inputNameCount, dir.getNameCount()).toString());
                    if (!outFile.exists() && !outFile.mkdirs()) {
                        throw new IOException("创建目录失败,目录:" + outFile.getAbsolutePath());
                    }
                }

                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                // 执行处理
                File outFile = new File(outFolder, file.subpath(inputNameCount, file.getNameCount()).toString());
                try {
                    handleFile(file.toFile(), outFile);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                return FileVisitResult.CONTINUE;
            }
        });

    }

    private static void handleFile(File inputFile, File outFile) throws IOException, InterruptedException {
        System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
        System.out.println("输入文件:" + inputFile);
        System.out.println("输出文件:" + outFile);

        if (outFile.exists() && !forceOverride) {
            return;
        }

        System.out.println("开始处理文件:" + inputFile.getAbsolutePath());

        if (isWebp(inputFile)) {

            try {
                ProcessResult processResult = doExecuteCmd(new String[]{convertFilePath, inputFile.getAbsolutePath(), outFile.getAbsolutePath()});

                System.out.println("执行结果:" + processResult.returnCode);

                System.out.println(processResult.out);
                System.out.println(processResult.err);

            } catch (ExecutionException e) {
                e.printStackTrace();
            }

        } else {
            copyFile(inputFile, outFile);
        }

    }


    private static ProcessResult doExecuteCmd(String[] args) throws IOException, InterruptedException, ExecutionException {

        Process exec = Runtime.getRuntime().exec(args);

        try {
            Future<String> outputFuture = getOutput(exec.getInputStream());
            Future<String> errorFuture = getOutput(exec.getErrorStream());
            int returnValue = exec.waitFor();

            ProcessResult result = new ProcessResult();
            result.returnCode = returnValue;
            result.out = outputFuture.get();
            result.err = errorFuture.get();
            return result;
        } finally {
            exec.destroy();
        }
    }


    /**
     * 获取输出
     *
     * @param outputStream 输出流
     * @return 输出字符
     */
    private static Future<String> getOutput(final InputStream outputStream) {

        return Executors.newCachedThreadPool().submit(() -> {
            StringBuilder outputStringBuilder = new StringBuilder();
            BufferedReader outputBufferedReader = new BufferedReader(new InputStreamReader(outputStream));
            String line;
            while ((line = outputBufferedReader.readLine()) != null) {
                outputStringBuilder.append(line).append("\n");
            }
            return outputStringBuilder.toString();
        });
    }

    private static boolean isWebp(File inputFile) {
        return inputFile.getName().endsWith(".gif");
    }

    private static void doCheck() {
        System.out.println("开始执行校验...");

        // 第一部分检查完成
        File inputFolder = new File(inputFolderPath);
        if (!inputFolder.exists()) {
            throw new IllegalArgumentException("输入目录不存在:" + inputFolderPath);
        }
        if (!inputFolder.isDirectory()) {
            throw new IllegalArgumentException("输入目录不是一个文件夹:" + inputFolderPath);
        }
        if (!inputFolder.canRead()) {
            throw new IllegalArgumentException("输入目录不能读取:" + inputFolderPath);
        }


        // 第二部分检查完成
        File outputFolder = new File(outputFolderPath);
        if (outputFolder.exists() && !inputFolder.isDirectory()) {
            throw new IllegalArgumentException("输出目录存在,但是不是一个文件夹:" + outputFolder);
        }

        if (!outputFolder.exists() && !outputFolder.mkdirs()) {
            throw new IllegalArgumentException("输出目录创建失败:" + outputFolder);
        }

        if (!outputFolder.canWrite()) {
            throw new IllegalArgumentException("输出目录无写入权限:" + outputFolder);
        }


        File convert = new File(convertFilePath);

        if (!convert.exists()) {
            throw new IllegalArgumentException("转换文件不存在," + convertFilePath);
        }

        if (!convert.canExecute()) {
            throw new IllegalArgumentException("转换文件没有执行权限," + convertFilePath);
        }

        System.out.println("校验完成");

    }


    /**
     * 复制文件
     *
     * @param sourceFile
     * @param destFile
     * @return
     * @throws IOException
     */
    public static void copyFile(File sourceFile, File destFile) throws IOException {

        if (!sourceFile.isFile()) {
            throw new IOException(sourceFile.getAbsolutePath() + "不是一个标准的文件");
        }

        if (destFile.exists() && !destFile.isFile()) {
            throw new IOException(destFile.getAbsolutePath() + "不是一个标准的文件");
        }

        File folder = destFile.getParentFile();
        if (!folder.exists() && !folder.mkdirs()) {
            throw new IOException("创建目录失败,目录:" + folder.getAbsolutePath());
        }

        if (!destFile.exists() && !destFile.createNewFile()) {
            throw new IOException("创建文件失败,文件:" + folder.getAbsolutePath());
        }

        try (FileInputStream fis = new FileInputStream(sourceFile); FileChannel in = fis.getChannel(); FileOutputStream fos = new FileOutputStream(destFile); FileChannel out = fos.getChannel();) {
            out.transferFrom(in, 0, in.size());

            final long srcLen = sourceFile.length(); // TODO See IO-386
            final long dstLen = destFile.length(); // TODO See IO-386
            if (srcLen != dstLen) {
                throw new IOException("Failed to copy full contents from '" + sourceFile + "' to '" + destFile + "' Expected length: " + srcLen + " Actual: " + dstLen);
            }

            destFile.setLastModified(sourceFile.lastModified());
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        }
    }

    public static class ProcessResult {
        protected int returnCode;
        protected String out;
        protected String err;
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值