国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

拒絕卡脖子 | 實現自己的圖片壓縮工具,想怎么壓就怎么壓

開發 開發工具
本文就基于SpringBoot結合thumbnailator實現圖片壓縮,坑已踩過拿去就用,也可以自己開發一個壓縮工具不被卡脖子。

當需要壓縮圖片時,到百度上搜索發現都是廣告,需要下載軟件和收費,貧窮不允許我這么任性。

好不容易找到一個在線免費壓縮圖片的網站,又有各種各樣的限制,比如我一直在用的在線免費壓縮工具【tinypng】,數量限制無所謂,但是圖片最大5M,往往不能滿足需求,如果需要使用高級功能需要付費。

當我找UI美眉幫忙把圖片處理小點時,嗯哼~~~,何不自己開發一個圖片處理工具。

目前軟件都會上傳圖片,一般都會對用戶上傳的圖片大小進行限制,并且上傳之后還要壓縮,這也可以為企業節省存儲成本的同時,還可提高上傳速率。

本文就基于SpringBoot結合thumbnailator實現圖片壓縮,坑已踩過拿去就用,也可以自己開發一個壓縮工具不被卡脖子。

本文大綱

  • 基于 thumbnailator 實現圖片壓縮,添加水印,旋轉等常用功能
  • 踩坑壓縮圖片反而變大的現象,并給出解決方案

創建SpringBoot工程

創建SpringBoot工程并引入相關依賴,根據Maven倉庫地址搜索最新版本為0.4.19,因0.4.8版本利用率最高,本工程也是用0.4.8版本,你可以自行選擇版本使用。

pom依賴

<!-- springboot-web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.7.4</version>
</dependency>
<!-- 圖片壓縮依賴 -->
<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.8</version>
</dependency>
<!-- 測試模塊 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
</dependency>

壓縮文件工具類

上傳文件時接口使用MultipartFile接收文件,所以我們壓縮圖片的方法也接收MultipartFile類型數據,并返回MultipartFile類型的數據【可根據實際情況調整參數類型】。

package com.stt.thumbnailator.util;

import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * 圖片處理工具類
 */
@Component
@Slf4j
public class ImgUtil {

    /**
     * 壓縮圖片,不修改尺寸
     * 1、接收 file 源文件,并判斷是否為空
     * 2、不修改原尺寸,按比例壓縮圖片
     * 3、將壓縮后的圖片封裝為 MultipartFile 類型返回
     * @param file
     * @return
     */
    public MultipartFile zipImg(MultipartFile file) {
        // 判空,并且大于20kb再壓縮
        if(file == null || file.getSize() <= 20 * 1024) {
            return file;
        }
        // 根據輸入流壓縮
        log.info("壓縮前圖片大小===》{}",file.getSize());
        // 字節文件輸出流,保存轉換后的圖片數據流
        ByteArrayOutputStream outputStream = null;
        // 通過輸入流轉換為 MultipartFile
        ByteArrayInputStream inputStream = null;
        try {
            outputStream = new ByteArrayOutputStream();
            Thumbnails.of(file.getInputStream())
                    .scale(1f) //按比例放大縮小 和size() 必須使用一個 不然會報錯
                    .outputQuality(0.5f) //輸出的圖片質量  0~1 之間,否則報錯
                    .toOutputStream(outputStream); //圖片輸出位置
            // 將 outputStream 轉換為 MultipartFile
            byte[] bytes = outputStream.toByteArray();
            inputStream = new ByteArrayInputStream(bytes);
            // 創建 MockMultipartFile 對象,該類在【spring-test】依賴中
            MockMultipartFile outFile = new MockMultipartFile(file.getOriginalFilename(), file.getOriginalFilename(), file.getContentType(), inputStream);
            log.info("壓縮后圖片大小===》{}",outFile.getSize());
            // 返回圖片
            return outFile;
        } catch (IOException e) {
            log.error("圖片壓縮失敗===》{}",e);
            throw new RuntimeException(e);
        }finally {
            // 關閉流
            try {
                outputStream.close();
                inputStream.close();
            } catch (IOException e) {
            }
        }
    }
}

上傳文件接口

package com.stt.thumbnailator.controller;

import com.stt.thumbnailator.util.ImgUtil;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 * 上傳文件接口
 */
@RestController
@RequestMapping("upload")
public class UploadController {

    private final ImgUtil imgUtil;

    public UploadController(ImgUtil imgUtil) {
        this.imgUtil = imgUtil;
    }

    /**
     * 上傳圖片,請求方式需要是POST請求
     * @param file
     */
    @PostMapping("img")
    public String uploadImg(MultipartFile file) {
        // 上傳圖片
        MultipartFile zipImg = imgUtil.zipImg(file);
        return "壓縮成功";
    }
}

application.yml

修改配置類默認文件上傳大小,默認1M根本不夠用。

spring:
  servlet:
    multipart:
      # 單個文件最大大小,默認1MB,該值根據實際需求調整
      max-file-size: 5MB
      # 一次請求文件最大大小,默認10MB,該值根據實際需求調整
      max-request-size: 20MB

測試

通過apifox快速發送請求,你也可以使用postman等工具。

發現控制臺輸出壓縮前和壓縮后文件大小,壓縮將近3倍,由outputQuality方法參數控制,值越小壓縮越嚴重,當然要保障圖片的清晰度,和產品需求適當調整。

親測在 0.3 時圖片會出現模糊

壓縮圖片并存儲

圖片一般都會存儲到文件服務器,這里暫時將圖片通過IO流存儲到本地,來看一下圖片清晰度。

/**
  * 壓縮圖片,不修改尺寸,存儲到本地
  * @param file
*/
public void zipImgToLocation(MultipartFile file) {
    // 判空,并且大于20kb再壓縮
    if(file == null || file.getSize() <= 20 * 1024) {
        return;
    }
    // 字節文件輸出流,保存轉換后的圖片數據流
    ByteArrayOutputStream outputStream = null;
    // 獲取文件名
    String originalFilename = file.getOriginalFilename();
    // 獲取文件后綴
    String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
    // 存儲文件位置和名字,改名字一般都隨機生成
    File localFile = new File("zipImg." + fileType);
    try {
        outputStream = new ByteArrayOutputStream();
        Thumbnails.of(file.getInputStream())
            .scale(1f) //按比例放大縮小 和size() 必須使用一個 不然會報錯
            .outputQuality(0.5f) //輸出的圖片質量  0~1 之間,否則報錯
            .toFile(localFile);
    } catch (IOException e) {
        log.error("圖片壓縮失敗===》{}",e);
        throw new RuntimeException(e);
    }finally {
        // 關閉流
        try {
            outputStream.close();
        } catch (IOException e) {
        }
    }
}

在個人電腦前看著并沒有差別,從3.68M壓縮到1.05M,這張圖上傳到頭條之后估計還得被平臺壓縮,總之可以根據outputQuality參數調整壓縮程度,別太模糊就行。

壓縮變大

壓縮也有坑啊,比如下方代碼,如果你將一張jpg的圖片按照原0.5的壓縮比壓縮后通過outputFormat方法轉換成png格式,圖片反而會被增大。

/**
  * 壓縮圖片,不修改尺寸,修改為png格式
  * @param file
*/
public void zipImgToPng(MultipartFile file) {
    // 判空,并且大于20kb再壓縮
    if(file == null || file.getSize() <= 20 * 1024) {
        return;
    }
    // 根據輸入流壓縮
    log.info("壓縮前圖片大小===》{}",file.getSize());
    // 字節文件輸出流,保存轉換后的圖片數據流
    ByteArrayOutputStream outputStream = null;
    try {
        outputStream = new ByteArrayOutputStream();
        Thumbnails.of(file.getInputStream())
            .scale(1f) //按比例放大縮小 和size() 必須使用一個 不然會報錯
            .outputQuality(0.5f) //輸出的圖片質量  0~1 之間,否則報錯
            .outputFormat("png") // 修改圖片為png格式
            .toOutputStream(outputStream);
        log.info("壓縮后圖片大小===》{}",outputStream.size());
    } catch (IOException e) {
        log.error("圖片壓縮失敗===》{}",e);
        throw new RuntimeException(e);
    }finally {
        // 關閉流
        try {
            outputStream.close();
        } catch (IOException e) {
        }
    }
}

圖片由3M增大到了20M

相似的問題,不少小伙伴也都遇到了

該問題在2022年12月31號更新的0.4.19版本中也并沒有解決,所以只能自行處理,也就有大佬總結出以下規則,Thumbnails.scale效果會導致圖片大小變大。

根據多次測試得來的結果:用jpg轉成jpg效果最佳

  • 當圖片為jpg時不要轉換直接壓縮
  • 當圖片為png時也可以直接壓縮,不要轉換
  • 當圖片為png時可以先轉換為jpg再壓縮也可以

添加水印

比如有以下水印,添加到任意一張圖片的右上角

工具類

/**
  * 添加水印
  * file: 原圖
  * markFile:水印
*/
public void addWatermark(MultipartFile file,MultipartFile markFile) {
    // 判空
    if(file == null) {
        return;
    }
    // 原圖文件流
    try {
        InputStream inputStream = file.getInputStream();
        InputStream markFileInputStream = markFile.getInputStream();
        // 讀取數據
        BufferedImage srcImg = ImageIO.read(inputStream);
        BufferedImage markImg = ImageIO.read(markFileInputStream);
        //原圖的寬高
        int srcWidth = srcImg.getWidth(null);
        int srcHeight = srcImg.getHeight(null);
        //水印圖片的寬高
        int markWidth = markImg.getWidth(null);
        int markHeight = markImg.getHeight(null);

        //計算輸出水印圖片的位置x和y軸
        int mark_x = srcWidth - srcWidth / 9;
        int mark_y = srcWidth / 9-srcWidth / 10;
        //計算輸出水印圖片的大小
        int mark_width = srcWidth / 10;
        int mark_height = (srcWidth * markHeight) / (10 * markWidth);

        //將水印圖片壓縮成輸出的大小
        markImg = Thumbnails.of(markImg).size(mark_width,mark_height).asBufferedImage();

        String originalFilename = file.getOriginalFilename();
        // 獲取文件后綴
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        File finalFile = new File("finalFile." + fileType);
        //watermark(位置,水印圖,透明度0.5f=50%透明度)
        //outputQuality(控制圖片的質量,1f=100%高質量)
        Thumbnails.of(srcImg)
            .size(srcWidth, srcHeight)
            .watermark(new Coordinate(mark_x,mark_y), markImg, 1f)
            .outputQuality(1f)
            .toFile(finalFile);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

接口需要接收兩張圖片,你也盡可以使用多文件上傳

@PostMapping("img/addWatermark")
public String addWatermark(@RequestParam("srcFile") MultipartFile srcFile,@RequestParam("markFile")  MultipartFile markFile) {
    // 上傳圖片
    imgUtil.addWatermark(srcFile,markFile);
    return "添加水印成功";
}

測試添加水印,發送請求時參數名一定要和接口中定義的@RequestParam 注解值相同

測試后發現右上角確實添加上了水印

圖片旋轉

可以通過 rotate 方法在順時針和逆時針方向旋轉圖片

/**
  * 旋轉圖片
*/
public void rotate(MultipartFile file) {
    try {
        String originalFilename = file.getOriginalFilename();
        // 獲取文件后綴
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        File finalFile = new File("finalFile." + fileType);
        Thumbnails.of(file.getInputStream())
            .rotate(90) // 角度,正數:順時針,負數:逆時針
            .toFile(finalFile);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

總結

  • 在壓縮,旋轉,添加水印,甚至裁剪時可以通過thumbnailator實現
  • 處理后的圖片可以根據需求進行存儲,也可以直接返回給客戶端
  • 處理后的數據可以是一個File文件,也可以是一個數據流,根據不同需求而定
  • 你可以在此基礎上開發自己的圖片處理工具給朋友或企業使用,豈不非常哇塞!

這就是我在使用的圖片處理技術,當然也有一些其他的方案,與其尋找各種方案哪種最優,不如挑選一種使用,進而自行優化,選擇技術的路上往往會浪費許多時間,你覺得呢?

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2022-06-14 07:29:51

squoosh壓縮工具開源

2020-08-21 09:58:16

谷歌Android工具

2016-04-20 15:36:38

圖片壓縮工具輕量化

2022-03-14 16:56:51

俄羅斯半導體產業制裁

2021-09-15 11:48:02

FacebookAndroid AppSuperpack技術

2025-07-31 01:47:00

2021-10-25 09:41:40

軟件 4G 5G

2019-05-24 09:47:09

ARM華為芯片

2023-09-21 18:16:57

Linux內核系統

2021-01-13 10:07:57

Linux 工具 開發

2023-10-19 08:23:50

wrkOpenResty工具

2010-01-05 16:58:43

圖片處理

2025-06-04 13:46:15

2025-11-25 08:48:56

2021-02-03 14:51:34

MySQL數據庫壓測工具

2012-05-30 10:36:26

Win7

2021-03-05 13:30:51

MySQL數據庫壓測工具

2020-12-03 09:57:34

MySQL壓測工具數據庫

2013-11-12 15:40:40

圖像壓縮

2021-03-02 09:56:33

技術研發指標
點贊
收藏

51CTO技術棧公眾號

69日小视频在线观看| 麻豆精品视频在线观看| 久久精品一区中文字幕| 在线观看操人| 777色狠狠一区二区三区| 日韩a在线观看| 亚洲成国产人片在线观看| 可以免费看污视频的网站| 中文在线资源观看网站视频免费不卡| 日本免费不卡一区二区| 国产成人精品午夜视频免费| 亚洲视频导航| 日韩成人精品视频| 一区二区不卡在线视频 午夜欧美不卡' | 国产精品爽爽ⅴa在线观看| 日韩av不卡一区| 色综合色综合网色综合| 99精品中文字幕在线不卡| 欧美多人乱p欧美4p久久| 久久成人福利| 国产精品电影网| 日韩免费av| 99国产高清| 欧美专区在线| 宅男av一区二区三区| 韩国v欧美v亚洲v日本v| av 日韩 人妻 黑人 综合 无码| 国产一区二区在线观看视频| 999一区二区三区| 99精品欧美一区| 一插菊花综合| 欧美日韩国产在线| 一本一道波多野毛片中文在线| 欧美一区二区三级| 日韩av一卡| 欧美人成在线视频| 国产传媒欧美日韩成人精品大片| 国产一区深夜福利| 国产精品外国| 黄色一级片在线看| 亚洲美女在线一区| 在线观看麻豆| 亚洲午夜精品久久久久久性色 | 欧美v国产在线一区二区三区| 91高清视频在线观看| 亚洲系列中文字幕| 日韩在线观看中文字幕| 成人免费高清完整版在线观看| 国产日韩综合| 日韩欧美在线播放视频| 亚洲超碰97人人做人人爱| 黄色av免费在线| 日韩在线精品视频| 日韩av久操| 97超碰人人爱| 一区二区三区波多野结衣在线观看| 亚洲国产精品一区二区www在线| 欧美 激情 在线| 亚洲精品v日韩精品| 美女写真理伦片在线看| 中文字幕亚洲国产| 久久社区一区| 亚洲永久激情精品| 亚洲欧洲99久久| 啦啦啦中文在线观看日本| 欧美国产中文字幕| 99精品国产99久久久久久福利| 日本韩国欧美在线观看| 欧美色xxxx| 在线观看欧美| 国产亚洲欧美另类一区二区三区| 99久久精品一区二区| 欧美日本韩国一区二区| 中文字幕在线成人| 欧美激情综合色综合啪啪| 久久久久久久久久网| 欧美最猛性xxxxx直播| 久久爱www.| 日韩精品电影网站| 17c精品麻豆一区二区免费| 国产第一页在线| 国产一区玩具在线观看| 99精品国产99久久久久久白柏| 搞黄视频免费在线观看| 久久99热精品这里久久精品| 日韩va亚洲va欧美va久久| 99re6热在线精品视频播放| 国产一区二区三区久久精品| 韩国亚洲精品| 国产日本视频| www.日韩免费| 青青国产91久久久久久| 亚洲成av人影片在线观看| 久久久精品一区| 秋霞成人午夜伦在线观看| 在线观看免费网站| 欧美激情一区二区三级高清视频| 久久精品国产77777蜜臀| 嫩草研究院在线观看| 68精品久久久久久欧美 | 丰满的护士2在线观看高清| 国产精品亚洲аv天堂网| 久久人人97超碰com| 国产传媒在线观看| 久久99精品久久久久久久久久| 一区二区三区高清| 日韩三级精品| 久久国产成人精品国产成人亚洲| 亚洲精品动漫100p| 久久综合九色综合欧美狠狠| 啊v在线视频| 成人在线免费观看视视频| 中文字幕的久久| 亚洲一区二区av| 欧美视频在线第一页| 精品国产99国产精品| 99国产精品私拍| 番号在线播放| 91精品婷婷国产综合久久蝌蚪| 亚洲自拍偷拍欧美| 国产一区二区三区不卡视频网站| 亚洲免费看av| 美日韩精品免费观看视频| 国产91丝袜在线播放九色| 校园春色亚洲| 天天操天天干天天玩| 亚洲精品之草原avav久久| 久久午夜精品| 欧美人与禽猛交乱配| 亚洲欧美国产一区二区| 精品国产乱码久久久久久免费| 狂野欧美一区| 青草青在线视频| 在线视频欧美一区| 国产一区二区三区精品久久久| 成人小视频在线| 亚洲成人毛片| 中文字幕国内自拍| 国产99久久精品一区二区永久免费 | 亚洲国产午夜| 在线a免费看| 欧美精品一区二区视频| 精品少妇一区二区三区免费观看 | 国产精品女上位| 日韩精选在线| 国产91精品捆绑调教| 国产精品女主播| 欧美在线视频你懂得| 久久精品亚洲| 性欧美超级视频| 男女男精品视频站| 国产精品美女免费| 欧美丝袜丝nylons| 精品午夜一区二区三区在线观看| 国产一区一一区高清不卡| www.日日操| 国产精品丝袜久久久久久高清| 欧美最猛性xxxxx直播| 日韩成人精品在线| 国产精品毛片无码| 中文在线二区| 日韩久久不卡| 色老头一区二区三区在线观看| 国产精品卡一卡二卡三| 91精品国产成人观看| 精品一性一色一乱农村| 国产免费毛卡片| 日本精品免费观看| 欧美日韩视频一区二区| 国产剧情一区二区三区| 日韩精品福利一区二区三区| 婷婷五月在线视频| 国产911在线观看| 欧洲精品久久久| 日韩一区二区三区免费观看| 成人av中文字幕| 国产精品传媒精东影业在线| 超碰中文在线| 99热热99| 免费日韩av电影| 欧美xxxx做受欧美.88| 狠狠躁夜夜躁人人爽超碰91| 麻豆国产欧美一区二区三区| 欧美美女黄色| 日本高清成人vr专区| 日本熟妇人妻中出| 国产精品免费一区二区三区| 中文字幕久久精品| 精品美女永久免费视频| 国产精品1区2区3区在线观看| 欧美理论视频| 少妇视频在线观看| 国产精品自拍三区| 日韩av片电影专区| 日韩一区二区电影网| 国产亚洲欧美一级| 久久综合九色综合欧美狠狠| 欧美禁忌电影网| 偷拍精品精品一区二区三区| 日本成人一区二区三区|