添加依賴
<!-- 圖檔縮略圖 -->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
Java壓縮圖檔案例1
部分字尾圖檔會出現壓縮失敗
//壓縮至範圍(50 壓縮到50KB)
@Value(value = "${jeecg.path.image-comprssion-to}")
private Integer imageComprssionTo;
//上傳檔案路徑(win D://opt//upFiles Linux /tang/upload)
@Value(value = "${jeecg.path.upload}")
private String uploadpath;
@Override
@Transactional(rollbackFor = Throwable.class)
public AiFileStorage uploadZip(String fileName) {
String originalFilename = "";//檔案名稱
String filePatha = uploadpath;
String filePathaBackup = uploadpath;
AiFileStorage aiFileStorage = new AiFileStorage();
try {
File addFile = new File(filePatha);
if (!addFile.exists()) {
addFile.mkdirs();
}
String findFfilePatha = filePatha + "/" + fileName;
File file = new File(findFfilePatha);
File savefile;
//伺服器上相同名稱的檔案,後面拼接 _compress + i
int i = -1;
do {
i++;
savefile = new File(filePatha + "/" + fileName.substring(0, fileName.lastIndexOf(".")) + "_compress" + (i == 0 ? "" : i)+ fileName.substring(fileName.indexOf(".")));
originalFilename = fileName.substring(0, fileName.lastIndexOf(".")) + "_compress" + (i == 0 ? "" : i) + fileName.substring(fileName.indexOf("."));
} while (savefile.exists());
filePatha += "/" + originalFilename;//絕對路徑
filePathaBackup += "/" + fileName;//源檔案
log.info("位址:" + filePatha);
log.info("檔案大小:" + new BigDecimal((double)file.length()/1024/1024).divide(new BigDecimal(1),2,BigDecimal.ROUND_HALF_UP)+"M");
log.info("檔案名" + originalFilename);
BigDecimal a = new BigDecimal((double)file.length()/1024/1024).divide(new BigDecimal(1),2,BigDecimal.ROUND_HALF_UP);
Integer productCode = imageComprssionTo;//圖檔壓縮範圍 超出的壓縮
BigDecimal b = new BigDecimal(StringUtils.getM(productCode));
File file_b = new File(filePatha);
if(a.compareTo(b) == 1){//a大于b,壓縮圖檔 a 源檔案大小 b 壓縮至大小
//壓縮圖檔
File file_c = new File(filePathaBackup);
Files.copy(file.toPath(),file_b.toPath());
Files.copy(file.toPath(),file_c.toPath());
ImageTool.compress("file:" + filePathaBackup,productCode,file_b.getAbsolutePath());
}else{
Files.copy(file.toPath(),file_b.toPath());
}
aiFileStorage.setCreateTime(new Timestamp(System.currentTimeMillis()));
aiFileStorage.setSize(file_b.length()/ 1024+" KB");
aiFileStorage.setType(2);
aiFileStorage.setSuffix(FileUtil.getExtensionName(file_b.getName()));
aiFileStorage.setName(file_b.getName());
aiFileStorage.setUrl(originalFilename);
aiFileStorageService.save(aiFileStorage);
return aiFileStorage;
} catch (NoSuchFileException e) {
e.printStackTrace();
throw new BadRequestException("檔案不存在");
} catch (IOException e) {
e.printStackTrace();
}
return new AiFileStorage();
}
檔案記錄實體類
package org.jeecg.modules.ai.entity;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 檔案存儲
* @Date: 2021-01-13
* @Version: V1.0
*/
@Data
@TableName("ai_file_storage")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="ai_file_storage對象", description="檔案存儲")
public class AiFileStorage implements Serializable {
private static final long serialVersionUID = 1L;
/**主鍵*/
@TableId(type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "主鍵")
private String id;
/**建立人*/
@ApiModelProperty(value = "建立人")
private String createBy;
/**上傳或同步的時間*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "上傳或同步的時間")
private Date createTime;
/**檔案名稱*/
@Excel(name = "檔案名稱", width = 15)
@ApiModelProperty(value = "檔案名稱")
private String name;
/**檔案大小*/
@Excel(name = "檔案大小", width = 15)
@ApiModelProperty(value = "檔案大小")
private String size;
/**檔案類型:私有或公開(1,私 2.共)*/
@Excel(name = "檔案類型:私有或公開(1,私 2.共)", width = 15)
@ApiModelProperty(value = "檔案類型:私有或公開(1,私 2.共)")
private Integer type;
/**檔案url*/
@Excel(name = "檔案url", width = 15)
@ApiModelProperty(value = "檔案url")
private String url;
/**檔案字尾*/
@Excel(name = "檔案字尾", width = 15)
@ApiModelProperty(value = "檔案字尾")
private String suffix;
}
FileUtil工具類
package org.jeecg.modules.ai.utils;
import cn.hutool.core.util.IdUtil;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
/**
* File工具類,擴充 hutool 工具包
* @author 億校雲
* @date 2018-12-27
*/
public class FileUtil extends cn.hutool.core.io.FileUtil {
/**
* 定義GB的計算常量
*/
private static final int GB = 1024 * 1024 * 1024;
/**
* 定義MB的計算常量
*/
private static final int MB = 1024 * 1024;
/**
* 定義KB的計算常量
*/
private static final int KB = 1024;
/**
* 格式化小數
*/
private static final DecimalFormat DF = new DecimalFormat("0.00");
/**
* MultipartFile轉File
* @param multipartFile
* @return
*/
public static File toFile(MultipartFile multipartFile){
// 擷取檔案名
String fileName = multipartFile.getOriginalFilename();
// 擷取檔案字尾
String prefix="."+getExtensionName(fileName);
File file = null;
try {
// 用uuid作為檔案名,防止生成的臨時檔案重複
file = File.createTempFile(IdUtil.simpleUUID(), prefix);
// MultipartFile to File
multipartFile.transferTo(file);
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
/**
* 删除
* @param files
*/
public static void deleteFile(File... files) {
for (File file : files) {
if (file.exists()) {
file.delete();
}
}
}
/**
* 擷取檔案擴充名
* @param filename
* @return
*/
public static String getExtensionName(String filename) {
if ((filename != null) && (filename.length() > 0)) {
int dot = filename.lastIndexOf('.');
if ((dot >-1) && (dot < (filename.length() - 1))) {
return filename.substring(dot + 1);
}
}
return filename;
}
/**
* Java檔案操作 擷取不帶擴充名的檔案名
* @param filename
* @return
*/
public static String getFileNameNoEx(String filename) {
if ((filename != null) && (filename.length() > 0)) {
int dot = filename.lastIndexOf('.');
if ((dot >-1) && (dot < (filename.length()))) {
return filename.substring(0, dot);
}
}
return filename;
}
/**
* 檔案大小轉換
* @param size
* @return
*/
public static String getSize(int size){
String resultSize = "";
if (size / GB >= 1) {
//如果目前Byte的值大于等于1GB
resultSize = DF.format(size / (float) GB) + "GB ";
} else if (size / MB >= 1) {
//如果目前Byte的值大于等于1MB
resultSize = DF.format(size / (float) MB) + "MB ";
} else if (size / KB >= 1) {
//如果目前Byte的值大于等于1KB
resultSize = DF.format(size / (float) KB) + "KB ";
} else {
resultSize = size + "B ";
}
return resultSize;
}
}
Java壓縮圖檔案例2
把圖檔轉換成流檔案
需要再添加個依賴
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
ImageTool工具類
package me.zhengjie.utils;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.imageio.stream.FileImageOutputStream;
import java.io.*;
import java.net.URL;
/**
* 圖檔處理類
*
* @author honghe
*/
public class ImageTool {
private static Logger logger = LoggerFactory.getLogger(
ImageTool.class);
private static final long DEFAULT_SIZE = 200 * 1024;
/*public static void main(String[] args) {
String picUrl = "C:/Users/admin/Desktop/url/picture/═╝╞м20.png";
compress(picUrl,50);
}*/
/**
* @param picUrl 圖檔位址
* @param desFileSize 壓縮大小
*/
public static byte[] compress(String picUrl, long desFileSize,String fileNameCopy) {
try {
URL url = new URL(picUrl);
byte[] imageBytes = IOUtils.toByteArray(url);
if (imageBytes == null || imageBytes.length <= 0) {
logger.error("圖檔資源加載失敗,請檢查連結位址!url:" + picUrl);
throw new RuntimeException("圖檔資源加載失敗,請檢查連結位址!url:" + picUrl);
}
if (imageBytes.length <= desFileSize * 1024) {
return imageBytes;
}
byte[] imageBytesCopy = imageBytes;
double accuracy = getAccuracy(imageBytes.length / 1024);
while (imageBytes.length > desFileSize * 1024) {
ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
Thumbnails.of(inputStream)
.scale(accuracy)
.outputQuality(accuracy)
.toOutputStream(outputStream);
imageBytes = outputStream.toByteArray();
}
logger.info("【圖檔壓縮】 | 圖檔原大小={}kb | 壓縮後大小={}kb | url={}",
imageBytesCopy.length / 1024, imageBytes.length / 1024, picUrl);
File file = new File(fileNameCopy);
if(!file.exists()) {
file.createNewFile();
}
FileWriter fileWriter =new FileWriter(file);
fileWriter.write("");
fileWriter.flush();
fileWriter.close();
FileImageOutputStream imageOutput = new FileImageOutputStream(new File(fileNameCopy));
imageOutput.write(imageBytes, 0, imageBytes.length);
imageOutput.close();
return imageBytes;
} catch (Exception e) {
logger.error("圖檔資源加載失敗,請檢查連結位址!url:" + picUrl);
throw new RuntimeException("圖檔資源加載失敗,請檢查連結位址!url:" + picUrl);
}
}
/**
* 對圖檔byte[]進行base64
*/
public static String base64ByPic(byte[] imageBatys) {
// 對位元組數組Base64編碼
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(imageBatys);
}
/**
* base64字元串轉換成圖檔
* 對位元組數組字元串進行Base64解碼并生成圖
*
* @param imgStr base64字元串
* @param imgFilePath 圖檔存放路徑
* @dateTime 2018-02-23 14:42:17
*/
public static boolean Base64ToImage(String imgStr, String imgFilePath) throws IOException {
OutputStream out = null;
if (StringUtils.isEmpty(imgStr)) {
return false;
}
BASE64Decoder decoder = new BASE64Decoder();
try {
// Base64解碼
byte[] b = decoder.decodeBuffer(imgStr);
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {// 調整異常資料
b[i] += 256;
}
}
out = new FileOutputStream(imgFilePath);
out.write(b);
out.flush();
out.close();
return true;
} catch (Exception e) {
return false;
} finally {
if (out != null) {
out.close();
}
}
}
/**
* 自動調節精度(經驗數值)
*
* @param size 源圖檔大小
* @return 圖檔壓縮品質比
*/
private static double getAccuracy(long size) {
double accuracy;
if (size < 900) {
accuracy = 0.85;
} else if (size < 2047) {
accuracy = 0.6;
} else if (size < 3275) {
accuracy = 0.44;
} else {
accuracy = 0.4;
}
return accuracy;
}
}
上傳圖檔Controller和Service
/**
* 上傳圖檔
* @param file
* @return
* @throws Exception
*/
@Log("上傳圖檔")
@PostMapping(value = "/picturesProduct")
public ResponseEntity picturesProduct(@RequestParam MultipartFile file, String productUrl){
Picture picture = pictureProductService.uploadZip(file,SecurityUtils.getUsername());
Map map = new HashMap();
map.put("errno",0);
map.put("id",picture.getId());
map.put("data",new String[]{picture.getUrl()});
return new ResponseEntity(map,HttpStatus.OK);
}
/**
* 上傳圖檔
* @param file
* @param username
* @return
*/
@CacheEvict(allEntries = true)
Picture uploadZip(MultipartFile file, String username);
Impl
@Override
@Transactional(rollbackFor = Throwable.class)
public Picture uploadZip(MultipartFile file, String username) {
String originalFilename = "";//檔案名稱
String originalFilenameBackup = "";//檔案名稱備份
// 檔案儲存路徑
String filePatha = pictureUrl;
String filePathaBackup = pictureUrl;
String urlProduct = "";
Picture picture = new Picture();
try {
File addFile = new File(filePatha);
if (!addFile.exists()) {
addFile.mkdirs();
}
//如果出現同名檔案,檔案名後面加随機數
String findFfilePatha = filePatha + "/" + file.getOriginalFilename();
File addNameFile = new File(findFfilePatha);
if (!addNameFile.exists()) {
originalFilename = FileUtil.getFileNameNoEx(file.getOriginalFilename())+"."+ FileUtil.getExtensionName(file.getOriginalFilename());
originalFilenameBackup = FileUtil.getFileNameNoEx(file.getOriginalFilename())+"Backup."+ FileUtil.getExtensionName(file.getOriginalFilename());
}else{
originalFilename = FileUtil.getFileNameNoEx(file.getOriginalFilename()) + System.currentTimeMillis() +"."+ FileUtil.getExtensionName(file.getOriginalFilename());
originalFilenameBackup = FileUtil.getFileNameNoEx(file.getOriginalFilename()) + System.currentTimeMillis() +".Backup"+ FileUtil.getExtensionName(file.getOriginalFilename());
}
filePatha += "/" + originalFilename;//絕對路徑
filePathaBackup += "/" + originalFilenameBackup;//備份檔案
urlProduct += "/" + originalFilename;//相對路徑
// 轉存檔案
log.info("位址:" + filePatha);
log.info("檔案大小:" + new BigDecimal((double)file.getSize()/1024/1024).divide(new BigDecimal(1),2,BigDecimal.ROUND_HALF_UP)+"M");
log.info("檔案名" + originalFilename);
File file_a = FileUtil.toFile(file);
BigDecimal a = new BigDecimal((double)file.getSize()/1024/1024).divide(new BigDecimal(1),2,BigDecimal.ROUND_HALF_UP);
BigDecimal b = new BigDecimal (0.3);//超過0.3M的圖檔進行壓縮
File file_b = new File(filePatha);
if(a.compareTo(b) == 1){//a大于b,壓縮圖檔
//壓縮圖檔
//第一種方法 部分格式圖檔會壓縮失敗
//Thumbnails.of(file_a.getAbsolutePath()).scale(1f).outputQuality(0.25f).toFile(file_b.getAbsolutePath());
//第二種 流檔案
File file_c = new File(filePathaBackup);//備份資料
Files.copy(file_a.toPath(),file_c.toPath());//不壓縮直接拷貝
ImageTool.compress("file:" + filePathaBackup,2000,file_b.getAbsolutePath());
log.info("壓縮成功:" + file_b.getAbsolutePath());
}else{
Files.copy(file_a.toPath(),file_b.toPath());//不壓縮直接拷貝
}
} catch (IOException e) {
e.printStackTrace();
}
picture.setCreateTime(new Timestamp(System.currentTimeMillis()));
picture.setSize(new BigDecimal((double)file.getSize()/1024/1024).divide(new BigDecimal(1),2,BigDecimal.ROUND_HALF_UP)+"M");
picture.setUsername(username);
picture.setFilename(originalFilename);
picture.setUrl("/static/picture" + urlProduct);//存本地相對位址
picture.setDelete(filePatha);
pictureRepository.save(picture);
return picture;
}
按指定大小把圖檔進行縮放(會遵循原圖高寬比例)
//按指定大小把圖檔進行縮和放(會遵循原圖高寬比例)
/此處把圖檔壓成400×500的縮略圖
Thumbnails.of(fromPic).size(400,500).toFile(toPic);//變為400*300,遵循原圖比例縮或放到400*某個高度
按照指定比例進行縮小和放大
//按照比例進行縮小和放大
Thumbnails.of(fromPic).scale(0.2f).toFile(toPic);//按比例縮小
Thumbnails.of(fromPic).scale(2f);//按比例放大
按指定的大小進行縮放(不遵循原圖比例)
//不按比例,就按指定的大小進行縮放
Thumbnails.of(fromPic).size(100, 100).keepAspectRatio(false).toFile(toPic);
//或者Thumbnails.of(fromPic).forceSize(100,100).toFile(toPic);
旋轉圖檔
//旋轉圖檔,rotate(角度),正數則為順時針,負數則為逆時針
Thumbnails.of(fromPic).size(200,200).rotate(90).toFile(toPic);
圖檔尺寸不變,壓縮圖檔檔案大小
//圖檔尺寸不變,壓縮圖檔檔案大小outputQuality實作,參數1為最高品質
Thumbnails.of(fromPic).scale(1f).outputQuality(0.25f).toFile(toPic);
給圖檔加水印
//給圖檔加水印,watermark(位置,水印圖,透明度)Positions.CENTER表示加在中間
Thumbnails.of(fromPic).size(400,400)
.watermark(Positions.CENTER,ImageIO.read(waterPic),0.5f)
.outputQuality(0.8f).toFile(toPic);
圖檔裁剪
//用sourceRegion()實作圖檔裁剪
//圖檔中心300*300的區域,Positions.CENTER表示中心,還有許多其他位置可選
Thumbnails.of(fromPic).sourceRegion(Positions.CENTER,300,300)
.size(300,300).toFile(toPic);
//圖檔中上區域300*300的區域
Thumbnails.of(fromPic).sourceRegion(Positions.TOP_CENTER,300,300)
.size(300,300).toFile(toPic);
轉換圖檔格式
格式由jpg變為png,圖檔大小沒變。
//用outputFormat(圖像格式)轉換圖檔格式,保持原尺寸不變
Thumbnails.of(fromPic).scale(1f).outputFormat("png")
.toFile("picture/png格式的圖檔.png");
輸出成檔案流OutputStream
//輸出成檔案流OutputStream
OutputStream os=new FileOutputStream(toPic);
Thumbnails.of(fromPic).size(120,120).toOutputStream(os);
輸出成BufferedImage
//輸出BufferedImage,asBufferedImage()傳回BufferedImage
BufferedImage bi=Thumbnails.of(fromPic).size(120,120).asBufferedImage();
ImageIO.write(bi,"jpg",toPic);
壓縮至指定圖檔尺寸,保持圖檔不變形,多餘部分裁剪掉
//壓縮至指定圖檔尺寸(例如:橫400高300),保持圖檔不變形,多餘部分裁剪掉(這個是引的網友的代碼)
BufferedImage image = ImageIO.read(fromPic);
Builder<BufferedImage> builder = null;
int imageWidth = image.getWidth();
int imageHeitht = image.getHeight();
if ((float)300 / 400 != (float)imageWidth / imageHeitht) {
if (imageWidth > imageHeitht) {
image = Thumbnails.of(fromPic).height(300).asBufferedImage();
} else {
image = Thumbnails.of(fromPic).width(400).asBufferedImage();
}
builder = Thumbnails.of(image).sourceRegion(Positions.CENTER, 400, 300).size(400, 300);
} else {
builder = Thumbnails.of(image).size(400, 300);
}
builder.outputFormat("jpg").toFile(toPic);
參考作者:https://blog.csdn.net/chenleixing/article/details/44685817
