From 6b634a46475f6d40dfc466b203e4610010e0757e Mon Sep 17 00:00:00 2001
From: "USER-Mr.Dai" <1224073217@qq.com>
Date: Thu, 21 May 2020 14:52:47 +0800
Subject: [PATCH 1/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96?=
=?UTF-8?q?=E7=B3=BB=E7=BB=9FCPU=E4=BD=BF=E7=94=A8=E7=8E=87=E7=AD=89?=
=?UTF-8?q?=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
hutool-system/pom.xml | 12 +-
.../main/java/cn/hutool/system/CpuInfo.java | 131 ++++++++++++++++++
.../java/cn/hutool/system/SystemUtil.java | 56 ++++++++
3 files changed, 198 insertions(+), 1 deletion(-)
create mode 100644 hutool-system/src/main/java/cn/hutool/system/CpuInfo.java
diff --git a/hutool-system/pom.xml b/hutool-system/pom.xml
index e17235fd3d..6e0a30373a 100644
--- a/hutool-system/pom.xml
+++ b/hutool-system/pom.xml
@@ -26,8 +26,18 @@
com.github.oshi
oshi-core
- 4.5.2
+ 4.6.1
provided
+
+ net.java.dev.jna
+ jna
+ 5.5.0
+
+
+ net.java.dev.jna
+ jna-platform
+ 5.5.0
+
diff --git a/hutool-system/src/main/java/cn/hutool/system/CpuInfo.java b/hutool-system/src/main/java/cn/hutool/system/CpuInfo.java
new file mode 100644
index 0000000000..c04feb4df3
--- /dev/null
+++ b/hutool-system/src/main/java/cn/hutool/system/CpuInfo.java
@@ -0,0 +1,131 @@
+package cn.hutool.system;
+
+import java.text.DecimalFormat;
+
+/**
+ *
+ * 2020-05-21 14:19
+ *
+ * @author Dai Yuanchuan
+ **/
+public class CpuInfo {
+
+ /**
+ * cpu核心数
+ */
+ private Integer cpuNum;
+
+ /**
+ * CPU总的使用率
+ */
+ private double toTal;
+
+ /**
+ * CPU系统使用率
+ */
+ private double sys;
+
+ /**
+ * CPU用户使用率
+ */
+ private double used;
+
+ /**
+ * CPU当前等待率
+ */
+ private double wait;
+
+ /**
+ * CPU当前空闲率
+ */
+ private double free;
+
+ /**
+ * CPU型号信息
+ */
+ private String cpuModel;
+
+ public CpuInfo() {
+ }
+
+ public CpuInfo(Integer cpuNum, double toTal, double sys, double used, double wait, double free, String cpuModel) {
+ this.cpuNum = cpuNum;
+ this.toTal = toTal;
+ this.sys = sys;
+ this.used = used;
+ this.wait = wait;
+ this.free = free;
+ this.cpuModel = cpuModel;
+ }
+
+ public Integer getCpuNum() {
+ return cpuNum;
+ }
+
+ public void setCpuNum(Integer cpuNum) {
+ this.cpuNum = cpuNum;
+ }
+
+ public double getToTal() {
+ return toTal;
+ }
+
+ public void setToTal(double toTal) {
+ this.toTal = toTal;
+ }
+
+ public double getSys() {
+ return sys;
+ }
+
+ public void setSys(double sys) {
+ this.sys = sys;
+ }
+
+ public double getUsed() {
+ return used;
+ }
+
+ public void setUsed(double used) {
+ this.used = used;
+ }
+
+ public double getWait() {
+ return wait;
+ }
+
+ public void setWait(double wait) {
+ this.wait = wait;
+ }
+
+ public double getFree() {
+ return free;
+ }
+
+ public void setFree(double free) {
+ this.free = free;
+ }
+
+ public String getCpuModel() {
+ return cpuModel;
+ }
+
+ public void setCpuModel(String cpuModel) {
+ this.cpuModel = cpuModel;
+ }
+
+ @Override
+ public String toString() {
+ DecimalFormat format = new DecimalFormat("#.00");
+ return "CpuInfo{" +
+ "cpu核心数=" + cpuNum +
+ ", CPU总的使用率=" + toTal +
+ ", CPU系统使用率=" + sys +
+ ", CPU用户使用率=" + used +
+ ", CPU当前等待率=" + wait +
+ ", CPU当前空闲率=" + free +
+ ", CPU利用率=" + Double.parseDouble(format.format((100 - getFree()))) +
+ ", CPU型号信息='" + cpuModel + '\'' +
+ '}';
+ }
+}
diff --git a/hutool-system/src/main/java/cn/hutool/system/SystemUtil.java b/hutool-system/src/main/java/cn/hutool/system/SystemUtil.java
index ee6c54ba25..ced92196b9 100644
--- a/hutool-system/src/main/java/cn/hutool/system/SystemUtil.java
+++ b/hutool-system/src/main/java/cn/hutool/system/SystemUtil.java
@@ -11,6 +11,7 @@ import java.lang.management.MemoryPoolMXBean;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
+import java.text.DecimalFormat;
import java.util.List;
import java.util.Properties;
@@ -18,6 +19,9 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.util.StrUtil;
+import cn.hutool.system.oshi.OshiUtil;
+import oshi.hardware.CentralProcessor;
+import oshi.util.Util;
/**
* Java的System类封装工具类。
@@ -484,6 +488,58 @@ public class SystemUtil {
return parentThread.activeCount();
}
+ // ------------------------------------------------------------------ cpu
+
+ /**
+ * 获取系统CPU 系统使用率、用户使用率、利用率等等 相关信息
+ *
+ * @return 系统 CPU 使用率 等信息
+ */
+ public static CpuInfo getCpuInfo() {
+ return setCpuInfo(OshiUtil.getProcessor(), 1000);
+ }
+
+ /**
+ * 获取系统CPU 系统使用率、用户使用率、利用率等等 相关信息
+ *
+ * @param waitingTime 设置等待时间
+ * @return 系统 CPU 使用率 等信息
+ */
+ public static CpuInfo getCpuInfo(long waitingTime) {
+ return setCpuInfo(OshiUtil.getProcessor(), waitingTime);
+ }
+
+ private static CpuInfo setCpuInfo(CentralProcessor processor, long waitingTime) {
+ CpuInfo cpuInfo = new CpuInfo();
+ // CPU信息
+ long[] prevTicks = processor.getSystemCpuLoadTicks();
+ // 这里必须要设置延迟
+ Util.sleep(waitingTime);
+ long[] ticks = processor.getSystemCpuLoadTicks();
+ long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
+ long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
+ long softIrq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
+ long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
+ long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
+ long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
+ long ioWait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
+ long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
+ long totalCpu = Math.max(user + nice + cSys + idle + ioWait + irq + softIrq + steal, 0);
+ DecimalFormat format = new DecimalFormat("#.00");
+ cpuInfo.setCpuNum(processor.getLogicalProcessorCount());
+ cpuInfo.setToTal(totalCpu);
+ cpuInfo.setSys(Double.parseDouble(format.format(cSys <= 0 ? 0 : (100d * cSys / totalCpu))));
+ cpuInfo.setUsed(Double.parseDouble(format.format(user <= 0 ? 0 : (100d * user / totalCpu))));
+ if (totalCpu == 0) {
+ cpuInfo.setWait(0);
+ } else {
+ cpuInfo.setWait(Double.parseDouble(format.format(100d * ioWait / totalCpu)));
+ }
+ cpuInfo.setFree(Double.parseDouble(format.format(idle <= 0 ? 0 : (100d * idle / totalCpu))));
+ cpuInfo.setCpuModel(processor.toString());
+ return cpuInfo;
+ }
+
// ------------------------------------------------------------------ Dump
/**
--
Gitee
From 8635fba190a0dab4320aefaa3be8c10f07832f3d Mon Sep 17 00:00:00 2001
From: "USER-Mr.Dai" <1224073217@qq.com>
Date: Thu, 21 May 2020 15:10:58 +0800
Subject: [PATCH 2/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96CPU?=
=?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=9A=84=E4=BD=BF=E7=94=A8=E6=A0=B7=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../test/java/cn/hutool/system/SystemUtilTest.java | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/hutool-system/src/test/java/cn/hutool/system/SystemUtilTest.java b/hutool-system/src/test/java/cn/hutool/system/SystemUtilTest.java
index 85048cf8b6..0e789f0488 100644
--- a/hutool-system/src/test/java/cn/hutool/system/SystemUtilTest.java
+++ b/hutool-system/src/test/java/cn/hutool/system/SystemUtilTest.java
@@ -5,25 +5,25 @@ import org.junit.Ignore;
import org.junit.Test;
public class SystemUtilTest {
-
+
@Test
@Ignore
public void dumpTest() {
SystemUtil.dumpSystemInfo();
}
-
+
@Test
public void getCurrentPidTest() {
long pid = SystemUtil.getCurrentPID();
Assert.assertTrue(pid > 0);
}
-
+
@Test
public void getJavaInfoTest() {
JavaInfo javaInfo = SystemUtil.getJavaInfo();
Assert.assertNotNull(javaInfo);
}
-
+
@Test
public void getOsInfoTest() {
OsInfo osInfo = SystemUtil.getOsInfo();
@@ -35,5 +35,11 @@ public class SystemUtilTest {
HostInfo hostInfo = SystemUtil.getHostInfo();
Assert.assertNotNull(hostInfo);
}
+
+ @Test
+ public void getCupInfo() {
+ CpuInfo cpuInfo = SystemUtil.getCpuInfo();
+ Assert.assertNotNull(cpuInfo);
+ }
}
--
Gitee
From c66499569d2cb62b7061fa97b7ebe18e24ce96e9 Mon Sep 17 00:00:00 2001
From: "USER-Mr.Dai" <1224073217@qq.com>
Date: Thu, 21 May 2020 17:48:23 +0800
Subject: [PATCH 3/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20=E5=9B=BE=E7=89=87?=
=?UTF-8?q?=E8=83=8C=E6=99=AF=E8=AF=86=E5=88=AB=E5=A4=84=E7=90=86=E3=80=81?=
=?UTF-8?q?=E8=83=8C=E6=99=AF=E6=9B=BF=E6=8D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../cn/hutool/core/img/BackgroundRemoval.java | 371 ++++++++++++++++++
.../main/java/cn/hutool/core/img/ImgUtil.java | 93 +++++
.../java/cn/hutool/core/img/ImgUtilTest.java | 19 +-
3 files changed, 478 insertions(+), 5 deletions(-)
create mode 100644 hutool-core/src/main/java/cn/hutool/core/img/BackgroundRemoval.java
diff --git a/hutool-core/src/main/java/cn/hutool/core/img/BackgroundRemoval.java b/hutool-core/src/main/java/cn/hutool/core/img/BackgroundRemoval.java
new file mode 100644
index 0000000000..a005b1dce9
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/img/BackgroundRemoval.java
@@ -0,0 +1,371 @@
+package cn.hutool.core.img;
+
+import cn.hutool.core.io.FileTypeUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+
+import javax.imageio.ImageIO;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 图片背景识别处理、背景替换、背景设置为矢量图
+ * 根据一定规则算出图片背景色的RGB值,进行替换
+ * 2020-05-21 16:36
+ *
+ * @author Dai Yuanchuan
+ **/
+public class BackgroundRemoval {
+
+ /**
+ * 目前暂时支持的图片类型数组
+ * 其他格式的不保证结果
+ */
+ public static String[] IMAGES_TYPE = {"jpg", "png"};
+
+ /**
+ * 背景移除
+ * 图片去底工具
+ * 将 "纯色背景的图片" 还原成 "透明背景的图片"
+ * 将纯色背景的图片转成矢量图
+ * 取图片边缘的像素点和获取到的图片主题色作为要替换的背景色
+ * 再加入一定的容差值,然后将所有像素点与该颜色进行比较
+ * 发现相同则将颜色不透明度设置为0,使颜色完全透明.
+ *
+ * @param inputPath 要处理图片的路径
+ * @param outputPath 输出图片的路径
+ * @param tolerance 容差值[根据图片的主题色,加入容差值,值的范围在0~255之间]
+ * @return 返回处理结果 true:图片处理完成 false:图片处理失败
+ */
+ public static boolean backgroundRemoval(String inputPath, String outputPath, int tolerance) {
+ return backgroundRemoval(new File(inputPath), new File(outputPath), tolerance);
+ }
+
+ /**
+ * 背景移除
+ * 图片去底工具
+ * 将 "纯色背景的图片" 还原成 "透明背景的图片"
+ * 将纯色背景的图片转成矢量图
+ * 取图片边缘的像素点和获取到的图片主题色作为要替换的背景色
+ * 再加入一定的容差值,然后将所有像素点与该颜色进行比较
+ * 发现相同则将颜色不透明度设置为0,使颜色完全透明.
+ *
+ * @param input 需要进行操作的图片
+ * @param output 最后输出的文件
+ * @param tolerance 容差值[根据图片的主题色,加入容差值,值的取值范围在0~255之间]
+ * @return 返回处理结果 true:图片处理完成 false:图片处理失败
+ */
+ public static boolean backgroundRemoval(File input, File output, int tolerance) {
+ return backgroundRemoval(input, output, null, tolerance);
+ }
+
+ /**
+ * 背景移除
+ * 图片去底工具
+ * 将 "纯色背景的图片" 还原成 "透明背景的图片"
+ * 将纯色背景的图片转成矢量图
+ * 取图片边缘的像素点和获取到的图片主题色作为要替换的背景色
+ * 再加入一定的容差值,然后将所有像素点与该颜色进行比较
+ * 发现相同则将颜色不透明度设置为0,使颜色完全透明.
+ *
+ * @param input 需要进行操作的图片
+ * @param output 最后输出的文件
+ * @param override 指定替换成的背景颜色 为null时背景为透明
+ * @param tolerance 容差值[根据图片的主题色,加入容差值,值的取值范围在0~255之间]
+ * @return 返回处理结果 true:图片处理完成 false:图片处理失败
+ */
+ public static boolean backgroundRemoval(File input, File output, Color override, int tolerance) {
+ if (fileTypeValidation(input, IMAGES_TYPE)) {
+ return false;
+ }
+ try {
+ // 获取图片左上、中上、右上、右中、右下、下中、左下、左中、8个像素点rgb的16进制值
+ BufferedImage bufferedImage = ImageIO.read(input);
+ // 图片输出的格式为 png
+ return ImageIO.write(backgroundRemoval(bufferedImage, override, tolerance), "png", output);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 背景移除
+ * 图片去底工具
+ * 将 "纯色背景的图片" 还原成 "透明背景的图片"
+ * 将纯色背景的图片转成矢量图
+ * 取图片边缘的像素点和获取到的图片主题色作为要替换的背景色
+ * 再加入一定的容差值,然后将所有像素点与该颜色进行比较
+ * 发现相同则将颜色不透明度设置为0,使颜色完全透明.
+ *
+ * @param bufferedImage 需要进行处理的图片流
+ * @param override 指定替换成的背景颜色 为null时背景为透明
+ * @param tolerance 容差值[根据图片的主题色,加入容差值,值的取值范围在0~255之间]
+ * @return 返回处理好的图片流
+ */
+ public static BufferedImage backgroundRemoval(BufferedImage bufferedImage, Color override, int tolerance) {
+ // 容差值 最大255 最小0
+ tolerance = Math.min(255, Math.max(tolerance, 0));
+ // 绘制icon
+ ImageIcon imageIcon = new ImageIcon(bufferedImage);
+ BufferedImage image = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(),
+ BufferedImage.TYPE_4BYTE_ABGR);
+ // 绘图工具
+ Graphics graphics = image.getGraphics();
+ graphics.drawImage(imageIcon.getImage(), 0, 0, imageIcon.getImageObserver());
+ // 需要删除的RGB元素
+ String[] removeRgb = getRemoveRgb(bufferedImage);
+ // 获取图片的大概主色调
+ String mainColor = getMainColor(bufferedImage);
+ int alpha = 0;
+ for (int y = image.getMinY(); y < image.getHeight(); y++) {
+ for (int x = image.getMinX(); x < image.getWidth(); x++) {
+ // 获取像素的16进制
+ int rgb = image.getRGB(x, y);
+ String hex = rgbToHex((rgb & 0xff0000) >> 16, (rgb & 0xff00) >> 8, (rgb & 0xff));
+ boolean isTrue = ArrayUtil.contains(removeRgb, hex) ||
+ areColorsWithinTolerance(hexToRgb(mainColor), new Color(Integer.parseInt(hex.substring(1), 16)), tolerance);
+ if (isTrue) {
+ rgb = override == null ? ((alpha + 1) << 24) | (rgb & 0x00ffffff) : override.getRGB();
+ }
+ image.setRGB(x, y, rgb);
+ }
+ }
+ graphics.drawImage(image, 0, 0, imageIcon.getImageObserver());
+ return image;
+ }
+
+ /**
+ * 背景移除
+ * 图片去底工具
+ * 将 "纯色背景的图片" 还原成 "透明背景的图片"
+ * 将纯色背景的图片转成矢量图
+ * 取图片边缘的像素点和获取到的图片主题色作为要替换的背景色
+ * 再加入一定的容差值,然后将所有像素点与该颜色进行比较
+ * 发现相同则将颜色不透明度设置为0,使颜色完全透明.
+ *
+ * @param outputStream 需要进行处理的图片字节数组流
+ * @param override 指定替换成的背景颜色 为null时背景为透明
+ * @param tolerance 容差值[根据图片的主题色,加入容差值,值的取值范围在0~255之间]
+ * @return 返回处理好的图片流
+ */
+ public static BufferedImage backgroundRemoval(ByteArrayOutputStream outputStream, Color override, int tolerance) {
+ try {
+ return backgroundRemoval(ImageIO.read(new ByteArrayInputStream(outputStream.toByteArray())), override, tolerance);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * 获取要删除的 RGB 元素
+ * 分别获取图片左上、中上、右上、右中、右下、下中、左下、左中、8个像素点rgb的16进制值
+ *
+ * @param image 图片流
+ * @return String数组 包含 各个位置的rgb数值
+ */
+ private static String[] getRemoveRgb(BufferedImage image) {
+ // 获取图片流的宽和高
+ int width = image.getWidth() - 1;
+ int height = image.getHeight() - 1;
+ // 左上
+ int leftUpPixel = image.getRGB(1, 1);
+ String leftUp = rgbToHex((leftUpPixel & 0xff0000) >> 16, (leftUpPixel & 0xff00) >> 8, (leftUpPixel & 0xff));
+ // 上中
+ int upMiddlePixel = image.getRGB(width / 2, 1);
+ String upMiddle = rgbToHex((upMiddlePixel & 0xff0000) >> 16, (upMiddlePixel & 0xff00) >> 8, (upMiddlePixel & 0xff));
+ // 右上
+ int rightUpPixel = image.getRGB(width, 1);
+ String rightUp = rgbToHex((rightUpPixel & 0xff0000) >> 16, (rightUpPixel & 0xff00) >> 8, (rightUpPixel & 0xff));
+ // 右中
+ int rightMiddlePixel = image.getRGB(width, height / 2);
+ String rightMiddle = rgbToHex((rightMiddlePixel & 0xff0000) >> 16, (rightMiddlePixel & 0xff00) >> 8, (rightMiddlePixel & 0xff));
+ // 右下
+ int lowerRightPixel = image.getRGB(width, height);
+ String lowerRight = rgbToHex((lowerRightPixel & 0xff0000) >> 16, (lowerRightPixel & 0xff00) >> 8, (lowerRightPixel & 0xff));
+ // 下中
+ int lowerMiddlePixel = image.getRGB(width / 2, height);
+ String lowerMiddle = rgbToHex((lowerMiddlePixel & 0xff0000) >> 16, (lowerMiddlePixel & 0xff00) >> 8, (lowerMiddlePixel & 0xff));
+ // 左下
+ int leftLowerPixel = image.getRGB(1, height);
+ String leftLower = rgbToHex((leftLowerPixel & 0xff0000) >> 16, (leftLowerPixel & 0xff00) >> 8, (leftLowerPixel & 0xff));
+ // 左中
+ int leftMiddlePixel = image.getRGB(1, height / 2);
+ String leftMiddle = rgbToHex((leftMiddlePixel & 0xff0000) >> 16, (leftMiddlePixel & 0xff00) >> 8, (leftMiddlePixel & 0xff));
+ // 需要删除的RGB元素
+ return new String[]{leftUp, upMiddle, rightUp, rightMiddle, lowerRight, lowerMiddle, leftLower, leftMiddle};
+ }
+
+ /**
+ * RGB颜色值转换成十六进制颜色码
+ *
+ * @param r 红(R)
+ * @param g 绿(G)
+ * @param b 蓝(B)
+ * @return 返回字符串形式的 十六进制颜色码 如
+ */
+ public static String rgbToHex(int r, int g, int b) {
+ // rgb 小于 255
+ boolean isRgb = (0 <= r && r <= 255) && (0 <= g && g <= 255) && (0 <= b && b <= 255);
+ if (isRgb) {
+ return String.format("#%02X%02X%02X", r, g, b);
+ } else {
+ throw new IllegalArgumentException("RGB颜色值只能为0~255之间的整数");
+ }
+ }
+
+ /**
+ * 十六进制颜色码转RGB颜色值
+ *
+ * @param hex 十六进制颜色码
+ * @return 返回 RGB颜色值
+ */
+ public static Color hexToRgb(String hex) {
+ return new Color(Integer.parseInt(hex.substring(1), 16));
+ }
+
+
+ /**
+ * 判断颜色是否在容差范围内
+ * 对比两个颜色的相似度,判断这个相似度是否小于 tolerance 容差值
+ *
+ * @param color1 颜色1
+ * @param color2 颜色2
+ * @param tolerance 容差值
+ * @return 返回true:两个颜色在容差值之内 false: 不在
+ */
+ public static boolean areColorsWithinTolerance(Color color1, Color color2, int tolerance) {
+ return areColorsWithinTolerance(color1, color2, new Color(tolerance, tolerance, tolerance));
+ }
+
+ /**
+ * 判断颜色是否在容差范围内
+ * 对比两个颜色的相似度,判断这个相似度是否小于 tolerance 容差值
+ *
+ * @param color1 颜色1
+ * @param color2 颜色2
+ * @param tolerance 容差色值
+ * @return 返回true:两个颜色在容差值之内 false: 不在
+ */
+ public static boolean areColorsWithinTolerance(Color color1, Color color2, Color tolerance) {
+ return (color1.getRed() - color2.getRed() < tolerance.getRed() && color1
+ .getRed() - color2.getRed() > -tolerance.getRed())
+ && (color1.getBlue() - color2.getBlue() < tolerance
+ .getBlue() && color1.getBlue() - color2.getBlue() > -tolerance
+ .getBlue())
+ && (color1.getGreen() - color2.getGreen() < tolerance
+ .getGreen() && color1.getGreen()
+ - color2.getGreen() > -tolerance.getGreen());
+ }
+
+ /**
+ * 获取图片大概的主题色
+ * 循环所有的像素点,取出出现次数最多的一个像素点的RGB值
+ *
+ * @param input 图片文件路径
+ * @return 返回一个图片的大概的色值 一个16进制的颜色码
+ */
+ public static String getMainColor(String input) {
+ return getMainColor(new File(input));
+ }
+
+ /**
+ * 获取图片大概的主题色
+ * 循环所有的像素点,取出出现次数最多的一个像素点的RGB值
+ *
+ * @param input 图片文件
+ * @return 返回一个图片的大概的色值 一个16进制的颜色码
+ */
+ public static String getMainColor(File input) {
+ try {
+ return getMainColor(ImageIO.read(input));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+
+ /**
+ * 获取图片大概的主题色
+ * 循环所有的像素点,取出出现次数最多的一个像素点的RGB值
+ *
+ * @param bufferedImage 图片流
+ * @return 返回一个图片的大概的色值 一个16进制的颜色码
+ */
+ public static String getMainColor(BufferedImage bufferedImage) {
+ if (bufferedImage == null) {
+ throw new IllegalArgumentException("图片流是空的");
+ }
+
+ // 存储图片的所有RGB元素
+ List list = new ArrayList<>();
+ for (int y = bufferedImage.getMinY(); y < bufferedImage.getHeight(); y++) {
+ for (int x = bufferedImage.getMinX(); x < bufferedImage.getWidth(); x++) {
+ int pixel = bufferedImage.getRGB(x, y);
+ list.add(((pixel & 0xff0000) >> 16) + "-" + ((pixel & 0xff00) >> 8) + "-" + (pixel & 0xff));
+ }
+ }
+
+ Map map = new HashMap<>(list.size());
+ for (String string : list) {
+ Integer integer = map.get(string);
+ if (integer == null) {
+ integer = 1;
+ } else {
+ integer++;
+ }
+ map.put(string, integer);
+ }
+ String max = "";
+ long num = 0;
+ for (Map.Entry entry : map.entrySet()) {
+ String key = entry.getKey();
+ Integer temp = entry.getValue();
+ if (StrUtil.isBlank(max) || temp > num) {
+ max = key;
+ num = temp;
+ }
+ }
+ String[] strings = max.split("-");
+ // rgb 的数量只有3个
+ int rgbLength = 3;
+ if (strings.length == rgbLength) {
+ return rgbToHex(Integer.parseInt(strings[0]), Integer.parseInt(strings[1]),
+ Integer.parseInt(strings[2]));
+ }
+ return "";
+ }
+
+ // -------------------------------------------------------------------------- private
+
+ /**
+ * 文件类型验证
+ * 根据给定文件类型数据,验证给定文件类型.
+ *
+ * @param input 需要进行验证的文件
+ * @param imagesType 文件包含的类型数组
+ * @return 返回布尔值 false:给定文件的文件类型在文件数组中 true:给定文件的文件类型 不在给定数组中。
+ */
+ private static boolean fileTypeValidation(File input, String[] imagesType) {
+ if (!input.exists()) {
+ throw new IllegalArgumentException("给定文件为空");
+ }
+ // 获取图片类型
+ String type = FileTypeUtil.getType(input);
+ // 类型对比
+ if (!ArrayUtil.contains(imagesType, type)) {
+ throw new IllegalArgumentException(StrUtil.format("文件类型{}不支持", type));
+ }
+ return false;
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java b/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java
index 74d0faaa1e..73b81adbba 100644
--- a/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java
@@ -1917,4 +1917,97 @@ public class ImgUtil {
}
return new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));
}
+
+ // ------------------------------------------------------------------------------------------------------ 背景图换算
+
+ /**
+ * 背景移除
+ * 图片去底工具
+ * 将 "纯色背景的图片" 还原成 "透明背景的图片"
+ * 将纯色背景的图片转成矢量图
+ * 取图片边缘的像素点和获取到的图片主题色作为要替换的背景色
+ * 再加入一定的容差值,然后将所有像素点与该颜色进行比较
+ * 发现相同则将颜色不透明度设置为0,使颜色完全透明.
+ *
+ * @param inputPath 要处理图片的路径
+ * @param outputPath 输出图片的路径
+ * @param tolerance 容差值[根据图片的主题色,加入容差值,值的范围在0~255之间]
+ * @return 返回处理结果 true:图片处理完成 false:图片处理失败
+ */
+ public static boolean backgroundRemoval(String inputPath, String outputPath, int tolerance) {
+ return BackgroundRemoval.backgroundRemoval(inputPath, outputPath, tolerance);
+ }
+
+ /**
+ * 背景移除
+ * 图片去底工具
+ * 将 "纯色背景的图片" 还原成 "透明背景的图片"
+ * 将纯色背景的图片转成矢量图
+ * 取图片边缘的像素点和获取到的图片主题色作为要替换的背景色
+ * 再加入一定的容差值,然后将所有像素点与该颜色进行比较
+ * 发现相同则将颜色不透明度设置为0,使颜色完全透明.
+ *
+ * @param input 需要进行操作的图片
+ * @param output 最后输出的文件
+ * @param tolerance 容差值[根据图片的主题色,加入容差值,值的取值范围在0~255之间]
+ * @return 返回处理结果 true:图片处理完成 false:图片处理失败
+ */
+ public static boolean backgroundRemoval(File input, File output, int tolerance) {
+ return BackgroundRemoval.backgroundRemoval(input, output, tolerance);
+ }
+
+ /**
+ * 背景移除
+ * 图片去底工具
+ * 将 "纯色背景的图片" 还原成 "透明背景的图片"
+ * 将纯色背景的图片转成矢量图
+ * 取图片边缘的像素点和获取到的图片主题色作为要替换的背景色
+ * 再加入一定的容差值,然后将所有像素点与该颜色进行比较
+ * 发现相同则将颜色不透明度设置为0,使颜色完全透明.
+ *
+ * @param input 需要进行操作的图片
+ * @param output 最后输出的文件
+ * @param override 指定替换成的背景颜色 为null时背景为透明
+ * @param tolerance 容差值[根据图片的主题色,加入容差值,值的取值范围在0~255之间]
+ * @return 返回处理结果 true:图片处理完成 false:图片处理失败
+ */
+ public static boolean backgroundRemoval(File input, File output, Color override, int tolerance) {
+ return BackgroundRemoval.backgroundRemoval(input, output, override, tolerance);
+ }
+
+ /**
+ * 背景移除
+ * 图片去底工具
+ * 将 "纯色背景的图片" 还原成 "透明背景的图片"
+ * 将纯色背景的图片转成矢量图
+ * 取图片边缘的像素点和获取到的图片主题色作为要替换的背景色
+ * 再加入一定的容差值,然后将所有像素点与该颜色进行比较
+ * 发现相同则将颜色不透明度设置为0,使颜色完全透明.
+ *
+ * @param bufferedImage 需要进行处理的图片流
+ * @param override 指定替换成的背景颜色 为null时背景为透明
+ * @param tolerance 容差值[根据图片的主题色,加入容差值,值的取值范围在0~255之间]
+ * @return 返回处理好的图片流
+ */
+ public static BufferedImage backgroundRemoval(BufferedImage bufferedImage, Color override, int tolerance) {
+ return BackgroundRemoval.backgroundRemoval(bufferedImage, override, tolerance);
+ }
+
+ /**
+ * 背景移除
+ * 图片去底工具
+ * 将 "纯色背景的图片" 还原成 "透明背景的图片"
+ * 将纯色背景的图片转成矢量图
+ * 取图片边缘的像素点和获取到的图片主题色作为要替换的背景色
+ * 再加入一定的容差值,然后将所有像素点与该颜色进行比较
+ * 发现相同则将颜色不透明度设置为0,使颜色完全透明.
+ *
+ * @param outputStream 需要进行处理的图片字节数组流
+ * @param override 指定替换成的背景颜色 为null时背景为透明
+ * @param tolerance 容差值[根据图片的主题色,加入容差值,值的取值范围在0~255之间]
+ * @return 返回处理好的图片流
+ */
+ public static BufferedImage backgroundRemoval(ByteArrayOutputStream outputStream, Color override, int tolerance) {
+ return BackgroundRemoval.backgroundRemoval(outputStream, override, tolerance);
+ }
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/img/ImgUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/img/ImgUtilTest.java
index 132a289655..35052ff1d3 100644
--- a/hutool-core/src/test/java/cn/hutool/core/img/ImgUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/img/ImgUtilTest.java
@@ -10,6 +10,7 @@ import java.awt.Font;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
+import java.io.File;
import java.io.IOException;
public class ImgUtilTest {
@@ -43,7 +44,7 @@ public class ImgUtilTest {
public void cutTest() {
ImgUtil.cut(FileUtil.file("d:/face.jpg"), FileUtil.file("d:/face_result.jpg"), new Rectangle(200, 200, 100, 100));
}
-
+
@Test
@Ignore
public void rotateTest() throws IOException {
@@ -81,29 +82,37 @@ public class ImgUtilTest {
public void sliceByRowsAndColsTest() {
ImgUtil.sliceByRowsAndCols(FileUtil.file("e:/pic/1.png"), FileUtil.file("e:/pic/dest"), 10, 10);
}
-
+
@Test
@Ignore
public void convertTest() {
ImgUtil.convert(FileUtil.file("e:/test2.png"), FileUtil.file("e:/test2Convert.jpg"));
}
-
+
@Test
@Ignore
public void writeTest() {
ImgUtil.write(ImgUtil.read("e:/test2.png"), FileUtil.file("e:/test2Write.jpg"));
}
-
+
@Test
@Ignore
public void compressTest() {
ImgUtil.compress(FileUtil.file("e:/pic/1111.png"), FileUtil.file("e:/pic/1111_target.jpg"), 0.8f);
}
-
+
@Test
@Ignore
public void copyTest() {
BufferedImage image = ImgUtil.copyImage(ImgUtil.read("f:/pic/test.png"), BufferedImage.TYPE_INT_RGB);
ImgUtil.write(image, FileUtil.file("f:/pic/test_dest.jpg"));
}
+
+ @Test
+ public void backgroundRemovalTest() {
+ // 图片 背景 换成 透明的
+ ImgUtil.backgroundRemoval("C:/Users/12240/Desktop/1.jpg", "C:/Users/12240/Desktop/2.jpg", 10);
+ // 图片 背景 换成 红色的
+ ImgUtil.backgroundRemoval(new File("C:/Users/12240/Desktop/1.jpg"), new File("C:/Users/12240/Desktop/3.jpg"), new Color(200, 0, 0), 10);
+ }
}
--
Gitee