欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-24 18:27:39
...

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

相关标签: java