哇哦,一个超级牛逼的图片格式!!使用它之后我们系统加载图片快了一倍!!! 图片格式转换webp学习!

news2024/11/27 14:38:23

什么是webp格式?

WebP 格式是一种图像文件格式。

它是由谷歌开发的,旨在提供一种高效的图像压缩方式,同时保持较好的图像质量。WebP 格式具有较小的文件体积,能够在一定程度上减少网络传输的数据量,提升网页加载速度。它支持有损压缩和无损压缩两种模式。

为什么要用webp格式?

  1. 减小文件大小
  2. 能显著降低图片文件的体积,节省存储空间。
  3. 减少网络传输的数据量,降低服务器的带宽压力。
  4. 提升加载效率
  5. 更快的加载速度可以改善用户体验。
  6. 快速加载的图片能让用户在浏览时感觉更流畅。
  7. 保持较好质量
  8. 在压缩过程中能较好地保留图像的细节和质量。

话不多说,上代码

首先 spring 三板斧

引入依赖:

因为webp在java中并没有上传到maven中央仓库,只能通过jar手动上传。点我下载文件

手动依赖方案:

<!--        图片格式转换为webp-->
<dependency>
    <groupId>com.github.nintha</groupId>
    <artifactId>webp-imageio-core</artifactId>
    <version>0.1.3</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/main/resources/libs/webp-imageio-core-0.1.3.jar</systemPath>
</dependency>

FileUtils

package cn.ideamake.file.common.utils;

import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.stream.StreamUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.ideamake.file.aop.MockMultipartFile;
import com.luciad.imageio.webp.WebPWriteParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Date;
import java.util.UUID;

@Slf4j
public class FileUtils {

    /**
     * 图片文件类型转换为webp格式
     * @return webp图片
     */
    public static File imagesToWebp(File file){
        try {
            String fileType = FileTypeUtil.getType(file);
            String outputWebpPath;
            if (!StrUtil.equalsAny(fileType, "jpg", "png", "jpeg")) {
                return null;
            }

            outputWebpPath = "/tmp/" + RandomUtil.randomString(32) + ".webp";
            // Obtain an image to encode from somewhere
            BufferedImage image = ImageIO.read(file);

            // Obtain a WebP ImageWriter instance
            ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/webp").next();

            // Configure encoding parameters
            WebPWriteParam writeParam = new WebPWriteParam(writer.getLocale());
            writeParam.setCompressionMode(WebPWriteParam.MODE_DEFAULT);

            // Configure the output on the ImageWriter
            writer.setOutput(new FileImageOutputStream(new File(outputWebpPath)));

            // Encode
            writer.write(null, new IIOImage(image, null, null), writeParam);

            return new File(outputWebpPath);
        } catch (Exception e) {
            log.error("上传失败", e);
            return null;
        }
    }

    public static MultipartFile imagesToWebp(MultipartFile multipartFile) throws IOException {
        File tmpFile = multipartFileToFile(multipartFile, "/tmp/multipartFileToFile"
                , RandomUtil.randomString(32) + "." + FileUtil.getSuffix(multipartFile.getOriginalFilename()));
        File file = imagesToWebp(tmpFile);
        return file == null ? multipartFile : new MockMultipartFile(file.getName(), FileUtil.getInputStream(file));
    }


    /**
     * MultipartFile类型文件转File
     * @return File类型文件
     */
    private static File multipartFileToFile(MultipartFile multipartFile, String filePath, String fileName){
        File f = null;
        File dir = new File(filePath);
        if (!dir.exists() && !dir.isDirectory()) {
            dir.mkdirs();
        }
        if(multipartFile.getSize() <= 0){
            multipartFile = null;
        } else {
            try {
                InputStream ins = multipartFile.getInputStream();
                f = new File(filePath + fileName);
                OutputStream os = Files.newOutputStream(f.toPath());
                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                while ((bytesRead = ins.read(buffer, 0, 8192)) != -1){
                    os.write(buffer, 0, bytesRead);
                }
                os.close();
                ins.close();
            } catch (IOException e) {
                log.error("转换file文件失败:{}", e);
            }
        }
        return f;
    }

    public static byte[] imagesToWebp(byte[] bytes, String fileName){
        File file = imagesToWebp(FileUtil.writeBytes(bytes, "/tmp/multipartFileToFile/" + fileName));
        return file == null ? bytes : FileUtil.readBytes(file);
    }

}

方法可自行重载扩展。

需要返回 MultipartFile 文件格式康我 MockMultipartFile 类

/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.ideamake.file.aop;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * Mock implementation of the {@link MultipartFile}
 * interface.
 *
 */
public class MockMultipartFile implements MultipartFile {

	private final String name;

	private final String originalFilename;

	@Nullable
	private final String contentType;

	private final byte[] content;


	/**
	 * Create a new MockMultipartFile with the given content.
	 * @param name the name of the file
	 * @param content the content of the file
	 */
	public MockMultipartFile(String name, @Nullable byte[] content) {
		this(name, name, null, content);
	}

	/**
	 * Create a new MockMultipartFile with the given content.
	 * @param name the name of the file
	 * @param contentStream the content of the file as stream
	 * @throws IOException if reading from the stream failed
	 */
	public MockMultipartFile(String name, InputStream contentStream) throws IOException {
		this(name, name, null, FileCopyUtils.copyToByteArray(contentStream));
	}

	/**
	 * Create a new MockMultipartFile with the given content.
	 * @param name the name of the file
	 * @param originalFilename the original filename (as on the client's machine)
	 * @param contentType the content type (if known)
	 * @param content the content of the file
	 */
	public MockMultipartFile(
			String name, @Nullable String originalFilename, @Nullable String contentType, @Nullable byte[] content) {

		Assert.hasLength(name, "Name must not be null");
		this.name = name;
		this.originalFilename = (originalFilename != null ? originalFilename : "");
		this.contentType = contentType;
		this.content = (content != null ? content : new byte[0]);
	}

	/**
	 * Create a new MockMultipartFile with the given content.
	 * @param name the name of the file
	 * @param originalFilename the original filename (as on the client's machine)
	 * @param contentType the content type (if known)
	 * @param contentStream the content of the file as stream
	 * @throws IOException if reading from the stream failed
	 */
	public MockMultipartFile(
			String name, @Nullable String originalFilename, @Nullable String contentType, InputStream contentStream)
			throws IOException {

		this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));
	}


	@Override
	public String getName() {
		return this.name;
	}

	@Override
	public String getOriginalFilename() {
		return this.originalFilename;
	}

	@Override
	@Nullable
	public String getContentType() {
		return this.contentType;
	}

	@Override
	public boolean isEmpty() {
		return (this.content.length == 0);
	}

	@Override
	public long getSize() {
		return this.content.length;
	}

	@Override
	public byte[] getBytes() {
		return this.content;
	}

	@Override
	public InputStream getInputStream() {
		return new ByteArrayInputStream(this.content);
	}

	@Override
	public void transferTo(File dest) throws IOException, IllegalStateException {
		FileCopyUtils.copy(this.content, dest);
	}

}

效果展示:

图片展示

webp

image

jpg

image

大小展示

webp

image

jpg

image

压缩了50% 而且还能保质保证图片效果!

本文到此结束啦,希望对你有所帮助!如果害怕下次找不到笔者关注点一点!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1659541.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网工常用工具——Xshell

今天给各位介绍一下&#xff0c;Xshell工具 Xshell是一款功能强大的终端模拟器&#xff0c;主要用于Windows操作系统&#xff0c;用于远程访问和管理服务器&#xff0c;允许用户通过SSH&#xff08;Secure Shell&#xff09;协议安全地连接到远程Linux/Unix服务器或其他支持SS…

DenseCLIP论文讲解

文章目录 简介方法总体框架 &#xff08;Language-Guided Dense Prediction&#xff09;上下文感知提示 &#xff08;Context-Aware Prompting&#xff09;应用实例 论文&#xff1a;DenseCLIP: Language-Guided Dense Prediction with Context-Aware Prompting 代码&#xff1…

Spring与AI结合-spring boot3整合AI组件

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 目录 写在前面 spring ai简介 单独整合al接口 整合Spring AI组件 起步条件 ​编辑 进行必要配置 写在最后 写在前面 本文介绍了springboot开发后端服务中&#xff0c;AI组件(Spring A…

淘宝扭蛋机小程序:开启惊喜购物的新纪元

一、引言 随着科技的飞速发展&#xff0c;我们的购物方式也在不断地更新换代。淘宝&#xff0c;作为国内领先的电商平台&#xff0c;始终致力于为用户提供更加便捷、有趣的购物体验。为了满足广大用户对于新鲜、刺激购物体验的追求&#xff0c;淘宝特别推出了扭蛋机小程序&…

[C++] const 成员函数

标题&#xff1a;[C] this指针 & const 成员函数 水墨不写bug 正文开始&#xff1a; 目录 &#xff08;一&#xff09;Cpp的面向对象编程 &#xff08;二&#xff09;this指针 &#xff08;三&#xff09;const修饰的成员函数 在正式讲解const修饰成员函数之前&#x…

实测ChatGPT插件真香用法!视频一键变脑图,高数作业轻松拿捏

Sam Altman诚不我欺&#xff1a; ChatGPT插件和联网功能终于在这两天向尊贵的Plus用户全面开放了。 像之前预告的一样&#xff0c;联网可以直接获取2021年9月之后的消息&#xff0c;插件也安排了70多个&#xff0c;购物订餐订机票等日常功能应有尽有&#xff0c;更专业的数学、…

网站未部署证书有何影响,如何解决?

如果您的网站没有ssl证书会有以下风险 1 浏览器标记为不安全 未安装证书的网站在访问时会有不安全的提示弹窗或者在网址栏直接显示不安全 2 影响企业信誉 当用户访问网站时看到不安全提示&#xff0c;会对网站的真实性和安全性产生怀疑&#xff0c;不敢轻易与该企业合作&…

Python-VBA函数之旅-setattr函数

目录 一、setattr函数的常见应用场景 二、setattr函数使用注意事项 三、如何用好setattr函数&#xff1f; 1、setattr函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://blog.csdn.net/ygb_1024?…

宏的优缺点?C++有哪些技术替代宏?(const)权限的平移、缩小

宏的优缺点&#xff1f; 优点&#xff1a; 1.增强代码的复用性。【减少冗余代码】 2.提高性能&#xff0c;提升代码运行效率。 缺点&#xff1a; 1.不方便调试宏。&#xff08;因为预编译阶段进行了替换&#xff09; 2.导致代码可读性差&#xff0c;可维护性差&#xff0…

小阳的戒S笔记

文章目录 写在前面2024年5月8日21:12:172024年5月9日21:48:242024年5月10日08:04:141、记录昨夜之身体变化2、自身制定之计划1.此亦乃要事&#xff0c;特定问了度娘与GPT&#xff0c;找时间还得咨询专业医师。2.通过跑步宣泄&#xff0c;同时锻炼身体3.我不会有压力&#xff0c…

替换spring-boot中的组件版本

spring-boot是一个用于简化开发的框架&#xff0c;引入spring-boot后会自动包含spring框架&#xff0c;通过引入xxx-start来完成指定组件的功能。比如&#xff1a; spring-boot-starter-web(嵌入 Tomcat 和 web 开发需要的 servlet 和 jsp 支持)spring-boot-starter-data-jpa(…

逻辑卷管理-LVM

目录 1. LVM的基本概念 2. Linux下创建和管理LVM 3. 环境准备 4. 物理卷管理 4.1. 创建物理卷 4.2. 显示物理卷 4.3. 删除物理卷 4. 卷组管理 4.1. 创建卷组 4.2. 显示卷组 4.3. 扩展卷组 4.4. 缩减卷组 4.5. 删除卷组 4.6. 分割卷组 4.7 组合卷组 5. 逻辑卷管…

VisualGDB:Linux静态库项目创建、编译及库的使用

接上篇《VisualGDB&#xff1a;Linux动态库项目创建、编译及库的使用》&#xff0c;静态库的创建和使用与动态库基本无差别&#xff0c;唯一需要做的就是指定项目生成静态库。 一、指定项目生成静态库 二、重新构建和编译项目 这里注意&#xff0c;同样要copy一个libxxx.so格式…

InternLM-Chat-7B部署调用-个人记录

一、环境准备 pip install modelscope1.9.5 pip install transformers4.35.2 二、下载模型 import torch from modelscope import snapshot_download, AutoModel, AutoTokenizer import os model_dir snapshot_download(Shanghai_AI_Laboratory/internlm-chat-7b, cache_di…

果味碳酸饮料二氧化碳气容量检测技术的创新与发展

果味碳酸饮料二氧化碳气容量检测技术的创新与发展 一、引言 随着健康饮食理念的普及和消费者对高品质饮料需求的增加&#xff0c;果味碳酸饮料的市场需求日益增长。在这一背景下&#xff0c;如何确保果味碳酸饮料的品质和口感成为了业界关注的焦点。二氧化碳气容量作为影响果味…

数据链路层之 以太网协议

以太网协议 这个协议即规定了数据链路层&#xff0c;同时也规定了物理层的内容。平时使用到的网线&#xff0c;其实也叫做“以太网线”&#xff08;遵守以太网协议的网线&#xff09;。 以太网帧格式 以太网数据帧 帧头 载荷 帧尾。 帧头&#xff1a;目的地址、源地址、类型…

Leetcode—232. 用栈实现队列【简单】

2024每日刷题&#xff08;131&#xff09; Leetcode—232. 用栈实现队列 实现代码 class MyQueue { public:MyQueue() {}void push(int x) {st.push(x);}int pop() {if(show.empty()) {if(empty()) {return -1;} else {int ans show.top();show.pop();return ans;}} else {i…

图像处理(二)

图像处理&#xff08;2&#xff09; 裁剪图片 from skimage import io,dataiimg io.imread(rD:\工坊\图像处理\十个勤天2.png)roiiimg[50:150,120:200,:]io.imshow(roi) 运行结果&#xff1a; 将图片进行二值化 from skimage import io,data,colorimg io.imread(r"…

TPB-1W 系列——1W 3KVDC 隔离 单输出 DC/DC 电源模块

TPB-1W系列产品是专门针对PCB上分布式电源系统中需要与输入电源隔离且输出精度要求较高的电源应用场合而设计。该产品适用于&#xff1b;1&#xff09;输入电源的电压变化≤5%&#xff1b;2&#xff09;输入输出之前要求隔离电压≥3000VDC&#xff1b;3&#xff09;对输出电压稳…

请求响应里面的日期参数

日期参数 需要在控制类使用DateTimeFormat注解 package com.ming.controller; ​ ​ import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.Rest…