CommonUtil.java 29 KB

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