CommonUtil.java 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. package org.springblade.common.utils;
  2. import cn.hutool.core.io.FileUtil;
  3. import cn.hutool.core.lang.func.Func;
  4. import cn.hutool.core.util.URLUtil;
  5. import cn.hutool.http.HttpUtil;
  6. import com.alibaba.fastjson.JSON;
  7. import com.alibaba.fastjson.JSONObject;
  8. import com.aliyuncs.utils.IOUtils;
  9. import com.drew.imaging.ImageMetadataReader;
  10. import com.drew.imaging.ImageProcessingException;
  11. import com.drew.metadata.Metadata;
  12. import com.drew.metadata.exif.ExifIFD0Directory;
  13. import com.google.common.collect.Lists;
  14. import com.google.common.collect.Maps;
  15. import org.apache.commons.imaging.ImageReadException;
  16. import org.apache.commons.imaging.Imaging;
  17. import org.apache.commons.lang.StringUtils;
  18. import org.springframework.util.CollectionUtils;
  19. import java.awt.*;
  20. import java.awt.color.ColorSpace;
  21. import java.awt.color.ICC_ColorSpace;
  22. import java.awt.geom.AffineTransform;
  23. import java.awt.image.AffineTransformOp;
  24. import java.awt.image.BufferedImage;
  25. import java.awt.image.ColorConvertOp;
  26. import java.io.*;
  27. import java.math.BigDecimal;
  28. import java.net.*;
  29. import java.time.LocalDate;
  30. import java.util.*;
  31. import java.util.List;
  32. import java.util.regex.Matcher;
  33. import java.util.regex.Pattern;
  34. import java.util.stream.Collectors;
  35. import java.util.stream.Stream;
  36. import java.util.zip.ZipEntry;
  37. import java.util.zip.ZipOutputStream;
  38. import com.drew.metadata.MetadataException;
  39. import javax.imageio.IIOImage;
  40. import javax.imageio.ImageIO;
  41. import javax.imageio.ImageWriteParam;
  42. import javax.imageio.ImageWriter;
  43. import net.coobird.thumbnailator.Thumbnails;
  44. /**
  45. * 通用工具类
  46. *
  47. * @author Chill
  48. */
  49. public class CommonUtil {
  50. private static final double INCH_TO_CM = 2.54;
  51. public static Boolean checkBigDecimal(Object value) {
  52. try {
  53. if (value != null && StringUtils.isNotEmpty(value.toString())) {
  54. new BigDecimal(value.toString());
  55. return true;
  56. }
  57. } catch (Exception e) {
  58. e.printStackTrace();
  59. }
  60. return false;
  61. }
  62. public static void removeFile(List<String> removeList) {
  63. for (String fileUrl : removeList) {
  64. try {
  65. FileUtil.del(new File(fileUrl));
  66. } catch (Exception e) {
  67. e.printStackTrace();
  68. }
  69. }
  70. }
  71. public static String handleNull(Object obj) {
  72. if (null == obj) {
  73. return "";
  74. } else {
  75. return obj.toString().trim();
  76. }
  77. }
  78. public static String join(Object... args) {
  79. if (args != null) {
  80. if (args.length > 2) {
  81. List<String> list = Arrays.stream(args).limit(args.length - 1).map(CommonUtil::handleNull).collect(Collectors.toList());
  82. String split = handleNull(args[args.length - 1]);
  83. return join(list, split);
  84. } else {
  85. return handleNull(args[0]);
  86. }
  87. } else {
  88. return "";
  89. }
  90. }
  91. public static String join(List<String> list, String split) {
  92. StringBuilder sb = new StringBuilder();
  93. if (list != null && list.size() > 0) {
  94. for (String str : list) {
  95. if (StringUtils.isNotEmpty(str)) {
  96. sb.append(str).append(split);
  97. }
  98. }
  99. if (sb.length() > 0 && StringUtils.isNotEmpty(split)) {
  100. sb.delete(sb.length() - split.length(), sb.length());
  101. }
  102. }
  103. return sb.toString();
  104. }
  105. public static Matcher matcher(String regex, String value) {
  106. Pattern pattern = Pattern.compile(regex);
  107. return pattern.matcher(value);
  108. }
  109. /**
  110. * 文件流转化为File
  111. */
  112. public static void convert(InputStream inputStream, String targetFile) throws IOException {
  113. // 创建文件输出流
  114. FileOutputStream outputStream = new FileOutputStream(targetFile);
  115. // 创建缓冲区
  116. byte[] buffer = new byte[1024];
  117. int bytesRead;
  118. // 从输入流读取数据并写入输出流
  119. while ((bytesRead = inputStream.read(buffer)) != -1) {
  120. outputStream.write(buffer, 0, bytesRead);
  121. }
  122. // 关闭流
  123. outputStream.close();
  124. inputStream.close();
  125. }
  126. /**
  127. * 根据OSS文件路径获取文件输入流
  128. */
  129. public static InputStream getOSSInputStream(String urlStr) {
  130. try {
  131. System.out.println("----前-------"+urlStr);
  132. urlStr = replaceOssUrl(urlStr);
  133. int lastIndex = urlStr.lastIndexOf("/") + 1;
  134. String fileName = urlStr.substring(lastIndex);
  135. urlStr = urlStr.substring(0, lastIndex) + URLEncoder.encode(fileName, "UTF-8").replace("+", "%20");
  136. //获取OSS文件流
  137. URL url = new URL(urlStr);
  138. URLConnection conn = url.openConnection();
  139. conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
  140. return conn.getInputStream();
  141. } catch (Exception e) {
  142. System.out.println("-----后------"+urlStr);
  143. return null;
  144. }
  145. }
  146. /**
  147. * 根据OSS文件路径获取文件输入流
  148. */
  149. public static InputStream getOSSInputStreamTow(String urlStr) throws Exception {
  150. //获取OSS文件流
  151. urlStr = replaceOssUrl(urlStr);
  152. URL imageUrl = new URL(urlStr);
  153. HttpURLConnection conn = null;
  154. try {
  155. conn = (HttpURLConnection) imageUrl.openConnection();
  156. conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
  157. return conn.getInputStream();
  158. } catch (IOException e) {
  159. e.printStackTrace();
  160. if (conn != null) {
  161. conn.disconnect(); //关闭网络连接
  162. }
  163. throw new Exception("获取图片输入流失败!URL:" + urlStr, e);
  164. }
  165. }
  166. /**
  167. * 获取字节数组
  168. */
  169. public static synchronized byte[] InputStreamToBytes(InputStream is) {
  170. BufferedInputStream bis = new BufferedInputStream(is);
  171. ByteArrayOutputStream os = new ByteArrayOutputStream();
  172. int date = -1;
  173. while (true) {
  174. try {
  175. if (!((date = bis.read()) != -1)) break;
  176. os.write(date);
  177. } catch (IOException e) {
  178. throw new RuntimeException(e);
  179. }
  180. }
  181. return os.toByteArray();
  182. }
  183. /**
  184. * 随机生成短信验证码
  185. *
  186. * @param length 生成长度
  187. */
  188. public static String getCharAndNumber(int length) {
  189. StringBuilder val = new StringBuilder();
  190. Random random = new Random();
  191. for (int i = 0; i < length; i++) {
  192. String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
  193. if ("char".equalsIgnoreCase(charOrNum)) {
  194. int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
  195. val.append((char) (choice + random.nextInt(26)));
  196. } else {
  197. val.append(random.nextInt(10));
  198. }
  199. }
  200. return val.toString();
  201. }
  202. /**
  203. * 判断参数是否是数字
  204. *
  205. * @param value 需要判断数据
  206. * @return 判断结果,数字则为true,反之false
  207. */
  208. public static boolean checkIsBigDecimal(Object value) {
  209. try {
  210. if (value != null && StringUtils.isNotEmpty(String.valueOf(value))) {
  211. new BigDecimal(String.valueOf(value));
  212. return true;
  213. } else {
  214. return false;
  215. }
  216. } catch (Exception e) {
  217. return false;
  218. }
  219. }
  220. /**
  221. * 根据每页信息分组
  222. */
  223. public static <T> List<List<T>> getBatchSize(List<T> allIds, int size) {
  224. List<List<T>> batchIds = new ArrayList<>();
  225. if (allIds == null || allIds.size() == 0 || size <= 0) {
  226. return batchIds;
  227. }
  228. int i = 0;
  229. List<T> tmp = new ArrayList<>();
  230. for (T map : allIds) {
  231. tmp.add(map);
  232. i++;
  233. if (i % size == 0 || i == allIds.size()) {
  234. batchIds.add(tmp);
  235. tmp = new ArrayList<>();
  236. }
  237. }
  238. return batchIds;
  239. }
  240. /**
  241. * @param src
  242. * @throws IOException
  243. * @throws ClassNotFoundException
  244. */
  245. public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {
  246. ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
  247. ObjectOutputStream out = new ObjectOutputStream(byteOut);
  248. out.writeObject(src);
  249. ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
  250. ObjectInputStream in = new ObjectInputStream(byteIn);
  251. @SuppressWarnings("unchecked")
  252. List<T> dest = (List<T>) in.readObject();
  253. return dest;
  254. }
  255. /**
  256. * Description: Java8 Stream分割list集合
  257. *
  258. * @param list 集合数据
  259. * @param splitSize 几个分割一组
  260. * @return 集合分割后的集合
  261. */
  262. public static <T> List<List<T>> splitList(List<T> list, int splitSize) {
  263. //判断集合是否为空
  264. if (CollectionUtils.isEmpty(list))
  265. return Collections.emptyList();
  266. //计算分割后的大小
  267. int maxSize = (list.size() + splitSize - 1) / splitSize;
  268. //开始分割
  269. return Stream.iterate(0, n -> n + 1)
  270. .limit(maxSize)
  271. .parallel()
  272. .map(a -> list.parallelStream().skip(a * splitSize).limit(splitSize).collect(Collectors.toList()))
  273. .filter(b -> !b.isEmpty())
  274. .collect(Collectors.toList());
  275. }
  276. /**
  277. * Map拆分 (指定分组大小)
  278. *
  279. * @param map Map
  280. * @param chunkSize 每个分组的大小 (>=1)
  281. * @param <K> Key
  282. * @param <V> Value
  283. * @return 子Map列表
  284. */
  285. public static <K, V> List<Map<K, V>> splitByChunkSize(Map<K, V> map, int chunkSize) {
  286. if (Objects.isNull(map) || map.isEmpty() || chunkSize < 1) {
  287. //空map或者分组大小<1,无法拆分
  288. return Collections.emptyList();
  289. }
  290. int mapSize = map.size(); //键值对总数
  291. int groupSize = mapSize / chunkSize + (mapSize % chunkSize == 0 ? 0 : 1); //计算分组个数
  292. List<Map<K, V>> list = Lists.newArrayListWithCapacity(groupSize); //子Map列表
  293. if (chunkSize >= mapSize) { //只能分1组的情况
  294. list.add(map);
  295. return list;
  296. }
  297. int count = 0; //每个分组的组内计数
  298. Map<K, V> subMap = Maps.newHashMapWithExpectedSize(chunkSize); //子Map
  299. for (Map.Entry<K, V> entry : map.entrySet()) {
  300. if (count < chunkSize) {
  301. //给每个分组放chunkSize个键值对,最后一个分组可能会装不满
  302. subMap.put(entry.getKey(), entry.getValue());
  303. count++; //组内计数+1
  304. } else {
  305. //结束上一个分组
  306. list.add(subMap); //当前分组装满了->加入列表
  307. //开始下一个分组
  308. subMap = Maps.newHashMapWithExpectedSize(chunkSize); //新的分组
  309. subMap.put(entry.getKey(), entry.getValue()); //添加当前键值对
  310. count = 1; //组内计数重置为1
  311. }
  312. }
  313. list.add(subMap); //添加最后一个分组
  314. return list;
  315. }
  316. /**
  317. * Map拆分(指定分组个数)
  318. *
  319. * @param map Map
  320. * @param groupSize 分组个数 (>=1)
  321. * @param <K> Key
  322. * @param <V> Value
  323. * @return 子Map列表
  324. */
  325. public static <K, V> List<Map<K, V>> splitByGroupSize(Map<K, V> map, int groupSize) {
  326. if (Objects.isNull(map) || map.isEmpty() || groupSize < 1) {
  327. //空map或者分组数<1,无法拆分
  328. return Collections.emptyList();
  329. }
  330. List<Map<K, V>> list = Lists.newArrayListWithCapacity(groupSize);
  331. if (groupSize == 1) { //只有1个分组的情况
  332. list.add(map);
  333. return list;
  334. }
  335. int mapSize = map.size(); //键值对总数
  336. int chunkIndex = 0; //当前分组的下标,[0, groupSize-1]
  337. int restCount = mapSize % groupSize; //平均后剩余的键值对数
  338. int chunkSize0 = mapSize / groupSize; //每个分组键值对数量
  339. int chunkSize1 = chunkSize0 + 1; //多分一个
  340. int chunkSize = chunkIndex < restCount ? chunkSize1 : chunkSize0; //实际每组的大小(前面的部分分组可能会多分1个)
  341. int count = 0; //每个分组的组内计数
  342. Map<K, V> subMap = Maps.newHashMapWithExpectedSize(chunkSize);//子Map
  343. for (Map.Entry<K, V> entry : map.entrySet()) {
  344. if (count < chunkSize) {
  345. //每个分组按实际分组大小(chunkSize)加入键值对
  346. subMap.put(entry.getKey(), entry.getValue());
  347. count++; //组内计数+1
  348. } else {
  349. //结束上一个分组
  350. list.add(subMap); //当前分组装满了->加入列表
  351. chunkIndex++; //分组个数+1
  352. //开始下一个分组
  353. chunkSize = chunkIndex < restCount ? chunkSize1 : chunkSize0; //重新计算分组大小
  354. subMap = Maps.newHashMapWithExpectedSize(chunkSize); //新的分组
  355. subMap.put(entry.getKey(), entry.getValue()); //添加当前键值对
  356. count = 1; //组内计数重置为1
  357. }
  358. }
  359. list.add(subMap); //添加最后一个分组
  360. return list;
  361. }
  362. /**
  363. * 流写入文件
  364. *
  365. * @param inputStream 文件输入流
  366. * @param file 输出文件
  367. */
  368. public static void inputStreamToFile(InputStream inputStream, File file) {
  369. try {
  370. OutputStream os = new FileOutputStream(file);
  371. int bytesRead = 0;
  372. byte[] buffer = new byte[8192];
  373. while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
  374. os.write(buffer, 0, bytesRead);
  375. }
  376. os.close();
  377. inputStream.close();
  378. } catch (Exception e) {
  379. e.printStackTrace();
  380. }
  381. }
  382. /**
  383. * 删除文件夹下所有文件
  384. *
  385. * @param path
  386. * @return
  387. */
  388. public static boolean deleteDir(String path) {
  389. File file = new File(path);
  390. if (!file.exists()) {//判断是否待删除目录是否存在
  391. System.err.println("The dir are not exists!");
  392. return false;
  393. }
  394. String[] content = file.list();//取得当前目录下所有文件和文件夹
  395. for (String name : content) {
  396. File temp = new File(path, name);
  397. if (temp.isDirectory()) {//判断是否是目录
  398. deleteDir(temp.getAbsolutePath());//递归调用,删除目录里的内容
  399. temp.delete();//删除空目录
  400. } else {
  401. if (!temp.delete()) {//直接删除文件
  402. System.err.println("Failed to delete " + name);
  403. }
  404. }
  405. }
  406. return true;
  407. }
  408. /**
  409. * 压缩指定路径下的文件夹
  410. *
  411. * @param filesPath
  412. * @throws Exception
  413. */
  414. public static void packageZip(String filesPath, String zipUrl) throws Exception {
  415. // 要被压缩的文件夹
  416. File file = new File(filesPath); //需要压缩的文件夹
  417. File folder = new File(zipUrl);
  418. if (!folder.exists() && !folder.isDirectory()) {
  419. folder.mkdirs();
  420. }
  421. File zipFile = new File(zipUrl + "/" + "localArchive.zip"); //放于和需要压缩的文件夹同级目录
  422. ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
  423. isDirectory(file, zipOut, "", true); //判断是否为文件夹
  424. zipOut.close();
  425. }
  426. public static void isDirectory(File file, ZipOutputStream zipOutputStream, String filePath, boolean flag) throws IOException {
  427. //判断是否为问加减
  428. if (file.isDirectory()) {
  429. File[] files = file.listFiles(); //获取该文件夹下所有文件(包含文件夹)
  430. filePath = flag == true ? file.getName() : filePath + File.separator + file.getName(); //首次为选中的文件夹,即根目录,之后递归实现拼接目录
  431. for (int i = 0; i < files.length; ++i) {
  432. //判断子文件是否为文件夹
  433. if (files[i].isDirectory()) {
  434. //进入递归,flag置false 即当前文件夹下仍包含文件夹
  435. isDirectory(files[i], zipOutputStream, filePath, false);
  436. } else {
  437. //不为文件夹则进行压缩
  438. InputStream input = new FileInputStream(files[i]);
  439. zipOutputStream.putNextEntry(new ZipEntry(filePath + File.separator + files[i].getName()));
  440. int temp = 0;
  441. while ((temp = input.read()) != -1) {
  442. zipOutputStream.write(temp);
  443. }
  444. input.close();
  445. }
  446. }
  447. } else {
  448. //将子文件夹下的文件进行压缩
  449. InputStream input = new FileInputStream(file);
  450. zipOutputStream.putNextEntry(new ZipEntry(file.getPath()));
  451. int temp = 0;
  452. while ((temp = input.read()) != -1) {
  453. zipOutputStream.write(temp);
  454. }
  455. input.close();
  456. }
  457. }
  458. /**
  459. * @param urlStr
  460. * @return 返回Url资源大小
  461. * @throws IOException
  462. */
  463. public static long getResourceLength(String urlStr) throws IOException {
  464. urlStr = replaceOssUrl(urlStr);
  465. URL url = new URL(urlStr);
  466. URLConnection urlConnection = url.openConnection();
  467. urlConnection.connect();
  468. //返回响应报文头字段Content-Length的值
  469. return urlConnection.getContentLength();
  470. }
  471. public static long getFileContentLength(String urlStr) {
  472. try {
  473. urlStr = replaceOssUrl(urlStr);
  474. System.out.println("获取文件大小:"+urlStr);
  475. URL url = new URL(urlStr);
  476. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  477. // 设置 HEAD 请求(只获取头部信息,不下载文件)
  478. conn.setRequestMethod("HEAD");
  479. // 设置超时(避免线上卡死)
  480. conn.setConnectTimeout(5000); // 5秒连接超时
  481. conn.setReadTimeout(5000); // 5秒读取超时
  482. // 发起请求
  483. conn.connect();
  484. // 获取 Content-Length
  485. long contentLength = conn.getContentLengthLong();
  486. // 关闭连接
  487. conn.disconnect();
  488. return contentLength;
  489. } catch (Exception e) {
  490. return 0L;
  491. }
  492. }
  493. public static long getFileSize(String fileUrl) throws IOException {
  494. URL url = new URL(fileUrl);
  495. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  496. // 使用 HEAD 请求(只获取文件信息,不下载内容)
  497. conn.setRequestMethod("HEAD");
  498. // 设置超时(避免卡死)
  499. conn.setConnectTimeout(5000); // 5秒连接超时
  500. conn.setReadTimeout(5000); // 5秒读取超时
  501. // 发起请求
  502. conn.connect();
  503. // 获取 Content-Length(文件大小)
  504. long fileSize = conn.getContentLengthLong();
  505. // 关闭连接
  506. conn.disconnect();
  507. return fileSize;
  508. }
  509. /**
  510. * 图片缩放、压缩、旋转处理
  511. *
  512. * @return
  513. * @throws IOException
  514. * @throws ImageProcessingException
  515. * @throws MetadataException
  516. */
  517. /* public static void main(String[] args) throws IOException, ImageProcessingException, MetadataException {
  518. // String imgurl = "/Users/hongchuangyanfa/Desktop/excel/432123.jpg";
  519. // String imgurl = "/Users/hongchuangyanfa/Desktop/excel/123.jpg";
  520. // String imgurl = "/Users/hongchuangyanfa/Downloads/03c1994653c4d59ab596e683a109e247 (1).jpg";
  521. String imgurl = "http://183.247.216.148:9000/minio-oss-chongqing/upload/20250414/03c1994653c4d59ab596e683a109e247.jpg";
  522. compressImage(imgurl);
  523. System.out.println("图片转换并保存成功!");
  524. }*/
  525. public static byte[] compressImage(String url) {
  526. // 读取原始图像(处理旋转问题)
  527. InputStream file = CommonUtil.getOSSInputStream(url);
  528. InputStream file2 = CommonUtil.getOSSInputStream(url);
  529. InputStream file3 = CommonUtil.getOSSInputStream(url);
  530. byte[] imageData = InputStreamToBytes(file);
  531. long sizeLimit = 1024 * 1024 * 5; //5M 1920 ×1080
  532. if (imageData.length <= sizeLimit) {
  533. return imageData;
  534. }
  535. try {
  536. Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(imageData));
  537. if (metadata.containsDirectoryOfType(ExifIFD0Directory.class)) {
  538. ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
  539. if (exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
  540. // 获取 Orientation 标签的值
  541. int orientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
  542. // 需要旋转图片
  543. // 1 无需纠正 2 水平翻转(镜像)3 垂直翻转(旋转180°) 4 水平翻转+垂直翻转 5 水平翻转+旋转90°
  544. // 6 旋转90° 7 水平翻转+旋转270° 8 +旋转270°
  545. if (orientation > 1) {
  546. ImageIO.scanForPlugins();
  547. BufferedImage originalImage = Imaging.getBufferedImage(file2);
  548. AffineTransform transform = new AffineTransform();
  549. if (orientation == 3) {
  550. transform.rotate(Math.PI, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
  551. } else if (orientation == 6) {
  552. transform.rotate(Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
  553. } else if (orientation == 8) {
  554. transform.rotate(-Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
  555. }
  556. AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
  557. originalImage = op.filter(originalImage, null);
  558. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  559. ImageIO.write(originalImage, "jpg", baos);
  560. imageData = baos.toByteArray();
  561. }
  562. }
  563. }
  564. // 缩放图像
  565. String formatName = "JPEG";
  566. ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
  567. String[] formats = ImageIO.getReaderFormatNames();
  568. System.out.println("----支持的格式-----: " + Arrays.toString(formats));
  569. // BufferedImage originalImage = ImageIO.read(file2);
  570. BufferedImage originalImage = Imaging.getBufferedImage(imageData); //.getBufferedImage(file3);
  571. int width = 1080;
  572. int height = 1920;
  573. Image scaledImage = originalImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
  574. BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
  575. resizedImage.getGraphics().drawImage(scaledImage, 0, 0, null);
  576. // 压缩图像
  577. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  578. ImageIO.write(resizedImage, formatName, baos);
  579. if (baos.size() <= sizeLimit) {
  580. // 图片大小已经小于等于目标大小,直接返回原始数据
  581. return baos.toByteArray();
  582. }
  583. float quality = 0.9f; // 初始化压缩质量
  584. int retries = 10; // 最多尝试 10 次
  585. while (baos.size() > sizeLimit && retries > 0) {
  586. // 压缩图像并重新计算压缩质量
  587. byte[] data = baos.toByteArray();
  588. bais = new ByteArrayInputStream(data);
  589. BufferedImage compressedImage = ImageIO.read(bais);
  590. baos.reset();
  591. ImageWriter writer = null;
  592. Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName);
  593. if (writers.hasNext()) {
  594. writer = writers.next();
  595. } else {
  596. throw new IllegalArgumentException("Unsupported image format: " + formatName);
  597. }
  598. ImageWriteParam writeParam = writer.getDefaultWriteParam();
  599. writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
  600. writeParam.setCompressionQuality(1);
  601. writer.setOutput(ImageIO.createImageOutputStream(baos));
  602. writer.write(null, new IIOImage(compressedImage, null, null), writeParam);
  603. writer.dispose();
  604. float ratio = sizeLimit * 1.0f / baos.size();
  605. quality *= Math.sqrt(ratio);
  606. retries--;
  607. }
  608. return baos.toByteArray();
  609. } catch (Exception e) {
  610. return imageData;
  611. }
  612. }
  613. public static byte[] compressImage(byte[] imageData) throws IOException, ImageProcessingException, MetadataException{
  614. // 读取原始图像(处理旋转问题)
  615. Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(imageData));
  616. if (metadata.containsDirectoryOfType(ExifIFD0Directory.class)) {
  617. ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
  618. if (exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
  619. // 获取 Orientation 标签的值
  620. int orientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
  621. // 需要旋转图片
  622. // 1 无需纠正 2 水平翻转(镜像)3 垂直翻转(旋转180°) 4 水平翻转+垂直翻转 5 水平翻转+旋转90°
  623. // 6 旋转90° 7 水平翻转+旋转270° 8 +旋转270°
  624. if (orientation > 1) {
  625. BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(imageData));
  626. AffineTransform transform = new AffineTransform();
  627. if (orientation == 3) {
  628. transform.rotate(Math.PI, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
  629. } else if (orientation == 6) {
  630. transform.rotate(Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
  631. } else if (orientation == 8) {
  632. transform.rotate(-Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
  633. }
  634. AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
  635. originalImage = op.filter(originalImage, null);
  636. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  637. ImageIO.write(originalImage, "jpg", baos);
  638. imageData = baos.toByteArray();
  639. }
  640. }
  641. }
  642. // 缩放图像
  643. String formatName = "JPEG";
  644. ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
  645. BufferedImage originalImage = null;
  646. try {
  647. originalImage = Imaging.getBufferedImage(imageData);
  648. } catch (ImageReadException e) {
  649. e.printStackTrace();
  650. }
  651. long sizeLimit = 1024*1024*5; //5M 1920 ×1080
  652. int width = 1080;
  653. int height = 1920;
  654. Image scaledImage = originalImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
  655. BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
  656. resizedImage.getGraphics().drawImage(scaledImage, 0, 0, null);
  657. // 压缩图像
  658. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  659. ImageIO.write(resizedImage, formatName, baos);
  660. if (baos.size() <= sizeLimit) {
  661. // 图片大小已经小于等于目标大小,直接返回原始数据
  662. return baos.toByteArray();
  663. }
  664. float quality = 0.9f; // 初始化压缩质量
  665. int retries = 10; // 最多尝试 10 次
  666. while (baos.size() > sizeLimit && retries > 0) {
  667. // 压缩图像并重新计算压缩质量
  668. byte[] data = baos.toByteArray();
  669. bais = new ByteArrayInputStream(data);
  670. BufferedImage compressedImage = ImageIO.read(bais);
  671. baos.reset();
  672. ImageWriter writer = null;
  673. Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName);
  674. if (writers.hasNext()) {
  675. writer = writers.next();
  676. } else {
  677. throw new IllegalArgumentException("Unsupported image format: " + formatName);
  678. }
  679. ImageWriteParam writeParam = writer.getDefaultWriteParam();
  680. writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
  681. writeParam.setCompressionQuality(1);
  682. writer.setOutput(ImageIO.createImageOutputStream(baos));
  683. writer.write(null, new IIOImage(compressedImage, null, null), writeParam);
  684. writer.dispose();
  685. float ratio = sizeLimit * 1.0f / baos.size();
  686. quality *= Math.sqrt(ratio);
  687. retries--;
  688. }
  689. return baos.toByteArray();
  690. }
  691. /**
  692. * 图片压缩
  693. *
  694. * @param imageData
  695. * @return
  696. * @throws IOException
  697. * @throws ImageProcessingException
  698. * @throws MetadataException
  699. */
  700. public static byte[] compressImage2(byte[] imageData) throws IOException {
  701. // 缩放图像
  702. String formatName = "JPEG";
  703. ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
  704. BufferedImage originalImage = ImageIO.read(bais);
  705. long sizeLimit = 512000; //358KB
  706. int width = originalImage.getWidth();
  707. int height = originalImage.getHeight();
  708. Image scaledImage = originalImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
  709. BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  710. resizedImage.getGraphics().drawImage(scaledImage, 0, 0, null);
  711. // 压缩图像
  712. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  713. ImageIO.write(resizedImage, formatName, baos);
  714. if (baos.size() <= sizeLimit) {
  715. // 图片大小已经小于等于目标大小,直接返回原始数据
  716. return baos.toByteArray();
  717. }
  718. float quality = 0.7f; // 初始化压缩质量
  719. int retries = 10; // 最多尝试 10 次
  720. while (baos.size() > sizeLimit && retries > 0) {
  721. // 压缩图像并重新计算压缩质量
  722. bais = new ByteArrayInputStream(imageData);
  723. originalImage = ImageIO.read(bais);
  724. float width2 = originalImage.getWidth() * quality;
  725. float height2 = originalImage.getHeight() * quality;
  726. scaledImage = originalImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
  727. resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  728. resizedImage.getGraphics().drawImage(scaledImage, 0, 0, null);
  729. // 压缩图像
  730. baos = new ByteArrayOutputStream();
  731. ImageIO.write(resizedImage, formatName, baos);
  732. if (baos.size() <= sizeLimit) {
  733. // 图片大小已经小于等于目标大小,直接返回原始数据
  734. return baos.toByteArray();
  735. }
  736. byte[] data = baos.toByteArray();
  737. bais = new ByteArrayInputStream(data);
  738. BufferedImage compressedImage = ImageIO.read(bais);
  739. baos.reset();
  740. ImageWriter writer = null;
  741. Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName);
  742. if (writers.hasNext()) {
  743. writer = writers.next();
  744. } else {
  745. throw new IllegalArgumentException("Unsupported image format: " + formatName);
  746. }
  747. ImageWriteParam writeParam = writer.getDefaultWriteParam();
  748. writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
  749. writeParam.setCompressionQuality(quality);
  750. writer.setOutput(ImageIO.createImageOutputStream(baos));
  751. writer.write(null, new IIOImage(compressedImage, null, null), writeParam);
  752. writer.dispose();
  753. float ratio = sizeLimit * 1.0f / baos.size();
  754. quality *= Math.sqrt(ratio);
  755. retries--;
  756. }
  757. return baos.toByteArray();
  758. }
  759. public static byte[] compressImage3(String url) throws IOException, ImageProcessingException, MetadataException {
  760. try(InputStream file = CommonUtil.getOSSInputStream(url)) {
  761. byte[] imageData = InputStreamToBytes(file);
  762. String extension = url.substring(url.lastIndexOf(".") + 1).toUpperCase();
  763. if ("JPG".equals(extension) || "JPEG".equals(extension)) {
  764. extension = "JPEG";
  765. }
  766. return compressImage3(imageData, extension);
  767. }
  768. }
  769. public static byte[] compressImage3(byte[] imageData, String formatName) throws ImageProcessingException, IOException, MetadataException {
  770. // 读取原始图像(处理旋转问题)
  771. int orientation = 1;
  772. Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(imageData));
  773. if (metadata.containsDirectoryOfType(ExifIFD0Directory.class)) {
  774. ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
  775. if (exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
  776. // 获取 Orientation 标签的值
  777. orientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
  778. }
  779. }
  780. // 缩放图像
  781. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  782. long sizeLimit = 1024*1024*5; //5M 1920 ×1080
  783. int width = 1080;
  784. int height = 1920;
  785. // 需要旋转图片
  786. // 1 无需纠正 2 水平翻转(镜像)3 垂直翻转(旋转180°) 4 水平翻转+垂直翻转 5 水平翻转+旋转90°
  787. // 6 旋转90° 7 水平翻转+旋转270° 8 +旋转270°
  788. float quality = 0.99f; // 初始化压缩质量
  789. int retries = 10; // 最多尝试 10 次
  790. double rotate = 0;
  791. if (orientation > 1) {
  792. if (orientation == 3) {
  793. rotate = 180;
  794. } else if (orientation == 6) {
  795. rotate = 90;
  796. } else if (orientation == 8) {
  797. rotate = 270;
  798. }
  799. }
  800. rotateAndScaleImageByThumbnails(new ByteArrayInputStream(imageData),baos, rotate, formatName, quality, width, height, true);
  801. if (baos.size() <= sizeLimit) {
  802. // 图片大小已经小于等于目标大小,直接返回原始数据
  803. return baos.toByteArray();
  804. }
  805. ByteArrayInputStream bais;
  806. while (baos.size() > sizeLimit && retries > 0) {
  807. // 压缩图像并重新计算压缩质量
  808. byte[] data = baos.toByteArray();
  809. bais = new ByteArrayInputStream(data);
  810. rotateAndScaleImageByThumbnails(bais,baos, 0, formatName, quality, width, height, true);
  811. float ratio = sizeLimit * 1.0f / baos.size();
  812. quality *= Math.sqrt(ratio);
  813. retries--;
  814. }
  815. return baos.toByteArray();
  816. }
  817. /**
  818. * @param is URL InputStream File BufferedImage path
  819. * @param os 输出流
  820. * @param rotate 旋转角度(正数顺时针,负数逆时针)
  821. * @param format 输出格式,jpg,jpeg,png等
  822. * @param quality 输出质量(0.0-1.0)
  823. * @param width 宽
  824. * @param height 高
  825. * @param keepAspectRatio 是否保持原比例
  826. */
  827. public static void rotateAndScaleImageByThumbnails(InputStream is, OutputStream os, double rotate, String format, double quality, int width, int height, boolean keepAspectRatio) throws IOException {
  828. Thumbnails.of(is)
  829. .size(width, height)
  830. .keepAspectRatio(keepAspectRatio)
  831. .rotate(rotate)
  832. .outputFormat(format)
  833. .outputQuality(quality)
  834. .toOutputStream(os);
  835. }
  836. /**
  837. * 根据起止日期获取工作日
  838. *
  839. * @return
  840. */
  841. public static int getWorkDays(LocalDate startTime, LocalDate endTime) {
  842. if (startTime.compareTo(endTime) > 0) {
  843. return -1;
  844. }
  845. // if (startTime.compareTo(endTime) == 0){
  846. // return 1;
  847. // }
  848. StringBuilder str = new StringBuilder();
  849. List<String> list = new ArrayList<>();
  850. while (!startTime.equals(endTime)) {
  851. str.append("d=" + startTime + "&");
  852. list.add(startTime.toString());
  853. startTime = startTime.plusDays(1L);
  854. }
  855. str.append("d=" + endTime + "&");
  856. list.add(endTime.toString());
  857. str.append("type=Y");
  858. String post = HttpUtil.get("http://timor.tech/api/holiday/batch?" + str.toString());
  859. JSONObject jsonObject = JSON.parseObject(post).getJSONObject("type");
  860. System.out.println(jsonObject);
  861. int workDays = 0;
  862. for (String s : list) {
  863. Map map = JSONObject.parseObject(jsonObject.get(s).toString(), Map.class);
  864. int type = (int) map.get("type");
  865. if (type == 0 || type == 3) {
  866. workDays++;
  867. }
  868. }
  869. return workDays;
  870. }
  871. public static String replaceOssUrl(String url) {
  872. //本地部署- 甬台温
  873. if (url.indexOf("183.247.216.148") >= 0 || url.indexOf("152.168.2.15") >= 0) {
  874. // 如果当前环境变量不包含linuxtesttest,则替换URL中的oss路径
  875. if (SystemUtils.isMacOs() || SystemUtils.isWindows()) {
  876. url = url.replace("https://", "http://").replace(":9000//", ":9000/");
  877. } else {
  878. url = url.replace("https://", "http://").replace("183.247.216.148", "152.168.2.15").replace(":9000//", ":9000/");
  879. }
  880. }
  881. return url;
  882. }
  883. /**
  884. * webp文件转字节数组
  885. *
  886. * @param
  887. * @return
  888. */
  889. public static byte[] webpToPngBytes(InputStream inputStream) {
  890. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  891. try {
  892. BufferedImage webpImage = ImageIO.read(inputStream);
  893. ImageIO.write(webpImage, "png", bos);
  894. } catch (Exception e) {
  895. e.printStackTrace();
  896. }
  897. return bos.toByteArray();
  898. }
  899. // 图片厘米转像素
  900. public static int cmToPx(double cm) {
  901. double pixelsPerCm = 90 / INCH_TO_CM;
  902. return (int) Math.round(cm * pixelsPerCm);
  903. }
  904. // 图片厘米转像素
  905. public static double pxToCm(int px) {
  906. double cmPerPixel = INCH_TO_CM / 90;
  907. //保留两位小数
  908. return Math.round(px * cmPerPixel * 100) / 100.0;
  909. }
  910. }