mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
ImgUtil中颜色相关方法剥离到ColorUtil中
This commit is contained in:
parent
746c18fdf7
commit
d1472f2bfe
@ -11,6 +11,7 @@
|
|||||||
* 【core 】 IdcardUtil增加convert18To15方法(issue#I5QYCP@Gitee)
|
* 【core 】 IdcardUtil增加convert18To15方法(issue#I5QYCP@Gitee)
|
||||||
* 【core 】 新增AnsiColors(改自Spring Boot)、AnsiColorWrapper,优化QrCodeUtil(pr#778@Gitee)
|
* 【core 】 新增AnsiColors(改自Spring Boot)、AnsiColorWrapper,优化QrCodeUtil(pr#778@Gitee)
|
||||||
* 【core 】 TemplateUtil的实现类增加getRawEngine方法(issues#2530@Github)
|
* 【core 】 TemplateUtil的实现类增加getRawEngine方法(issues#2530@Github)
|
||||||
|
* 【core 】 ImgUtil中颜色相关方法剥离到ColorUtil中
|
||||||
|
|
||||||
### 🐞Bug修复
|
### 🐞Bug修复
|
||||||
* 【core 】 修复ObjectUtil.defaultIfXXX中NPE问题(pr#2603@Github)
|
* 【core 】 修复ObjectUtil.defaultIfXXX中NPE问题(pr#2603@Github)
|
||||||
|
262
hutool-core/src/main/java/cn/hutool/core/img/ColorUtil.java
Normal file
262
hutool-core/src/main/java/cn/hutool/core/img/ColorUtil.java
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
package cn.hutool.core.img;
|
||||||
|
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 颜色工具类
|
||||||
|
*
|
||||||
|
* @since 5.8.7
|
||||||
|
*/
|
||||||
|
public class ColorUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB颜色范围上限
|
||||||
|
*/
|
||||||
|
private static final int RGB_COLOR_BOUND = 256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color对象转16进制表示,例如#fcf6d6
|
||||||
|
*
|
||||||
|
* @param color {@link Color}
|
||||||
|
* @return 16进制的颜色值,例如#fcf6d6
|
||||||
|
* @since 4.1.14
|
||||||
|
*/
|
||||||
|
public static String toHex(Color color) {
|
||||||
|
return toHex(color.getRed(), color.getGreen(), color.getBlue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RGB颜色值转换成十六进制颜色码
|
||||||
|
*
|
||||||
|
* @param r 红(R)
|
||||||
|
* @param g 绿(G)
|
||||||
|
* @param b 蓝(B)
|
||||||
|
* @return 返回字符串形式的 十六进制颜色码 如
|
||||||
|
*/
|
||||||
|
public static String toHex(int r, int g, int b) {
|
||||||
|
// rgb 小于 255
|
||||||
|
if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) {
|
||||||
|
throw new IllegalArgumentException("RGB must be 0~255!");
|
||||||
|
}
|
||||||
|
return String.format("#%02X%02X%02X", r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将颜色值转换成具体的颜色类型 汇集了常用的颜色集,支持以下几种形式:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* 1. 颜色的英文名(大小写皆可)
|
||||||
|
* 2. 16进制表示,例如:#fcf6d6或者$fcf6d6
|
||||||
|
* 3. RGB形式,例如:13,148,252
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* 方法来自:com.lnwazg.kit
|
||||||
|
*
|
||||||
|
* @param colorName 颜色的英文名,16进制表示或RGB表示
|
||||||
|
* @return {@link Color}
|
||||||
|
* @since 4.1.14
|
||||||
|
*/
|
||||||
|
public static Color getColor(String colorName) {
|
||||||
|
if (StrUtil.isBlank(colorName)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
colorName = colorName.toUpperCase();
|
||||||
|
|
||||||
|
if ("BLACK".equals(colorName)) {
|
||||||
|
return Color.BLACK;
|
||||||
|
} else if ("WHITE".equals(colorName)) {
|
||||||
|
return Color.WHITE;
|
||||||
|
} else if ("LIGHTGRAY".equals(colorName) || "LIGHT_GRAY".equals(colorName)) {
|
||||||
|
return Color.LIGHT_GRAY;
|
||||||
|
} else if ("GRAY".equals(colorName)) {
|
||||||
|
return Color.GRAY;
|
||||||
|
} else if ("DARKGRAY".equals(colorName) || "DARK_GRAY".equals(colorName)) {
|
||||||
|
return Color.DARK_GRAY;
|
||||||
|
} else if ("RED".equals(colorName)) {
|
||||||
|
return Color.RED;
|
||||||
|
} else if ("PINK".equals(colorName)) {
|
||||||
|
return Color.PINK;
|
||||||
|
} else if ("ORANGE".equals(colorName)) {
|
||||||
|
return Color.ORANGE;
|
||||||
|
} else if ("YELLOW".equals(colorName)) {
|
||||||
|
return Color.YELLOW;
|
||||||
|
} else if ("GREEN".equals(colorName)) {
|
||||||
|
return Color.GREEN;
|
||||||
|
} else if ("MAGENTA".equals(colorName)) {
|
||||||
|
return Color.MAGENTA;
|
||||||
|
} else if ("CYAN".equals(colorName)) {
|
||||||
|
return Color.CYAN;
|
||||||
|
} else if ("BLUE".equals(colorName)) {
|
||||||
|
return Color.BLUE;
|
||||||
|
} else if ("DARKGOLD".equals(colorName)) {
|
||||||
|
// 暗金色
|
||||||
|
return hexToColor("#9e7e67");
|
||||||
|
} else if ("LIGHTGOLD".equals(colorName)) {
|
||||||
|
// 亮金色
|
||||||
|
return hexToColor("#ac9c85");
|
||||||
|
} else if (StrUtil.startWith(colorName, '#')) {
|
||||||
|
return hexToColor(colorName);
|
||||||
|
} else if (StrUtil.startWith(colorName, '$')) {
|
||||||
|
// 由于#在URL传输中无法传输,因此用$代替#
|
||||||
|
return hexToColor("#" + colorName.substring(1));
|
||||||
|
} else {
|
||||||
|
// rgb值
|
||||||
|
final List<String> rgb = StrUtil.split(colorName, ',');
|
||||||
|
if (3 == rgb.size()) {
|
||||||
|
final Integer r = Convert.toInt(rgb.get(0));
|
||||||
|
final Integer g = Convert.toInt(rgb.get(1));
|
||||||
|
final Integer b = Convert.toInt(rgb.get(2));
|
||||||
|
if (false == ArrayUtil.hasNull(r, g, b)) {
|
||||||
|
return new Color(r, g, b);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取一个RGB值对应的颜色
|
||||||
|
*
|
||||||
|
* @param rgb RGB值
|
||||||
|
* @return {@link Color}
|
||||||
|
* @since 4.1.14
|
||||||
|
*/
|
||||||
|
public static Color getColor(int rgb) {
|
||||||
|
return new Color(rgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16进制的颜色值转换为Color对象,例如#fcf6d6
|
||||||
|
*
|
||||||
|
* @param hex 16进制的颜色值,例如#fcf6d6
|
||||||
|
* @return {@link Color}
|
||||||
|
* @since 4.1.14
|
||||||
|
*/
|
||||||
|
public static Color hexToColor(String hex) {
|
||||||
|
return getColor(Integer.parseInt(StrUtil.removePrefix(hex, "#"), 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 叠加颜色
|
||||||
|
* @param color1 颜色1
|
||||||
|
* @param color2 颜色2
|
||||||
|
* @return 叠加后的颜色
|
||||||
|
*/
|
||||||
|
public static Color add(Color color1, Color color2) {
|
||||||
|
double r1 = color1.getRed();
|
||||||
|
double g1 = color1.getGreen();
|
||||||
|
double b1 = color1.getBlue();
|
||||||
|
double a1 = color1.getAlpha();
|
||||||
|
double r2 = color2.getRed();
|
||||||
|
double g2 = color2.getGreen();
|
||||||
|
double b2 = color2.getBlue();
|
||||||
|
double a2 = color2.getAlpha();
|
||||||
|
int r = (int) ((r1 * a1 / 255 + r2 * a2 / 255) / (a1 / 255 + a2 / 255));
|
||||||
|
int g = (int) ((g1 * a1 / 255 + g2 * a2 / 255) / (a1 / 255 + a2 / 255));
|
||||||
|
int b = (int) ((b1 * a1 / 255 + b2 * a2 / 255) / (a1 / 255 + a2 / 255));
|
||||||
|
return new Color(r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成随机颜色
|
||||||
|
*
|
||||||
|
* @return 随机颜色
|
||||||
|
* @since 3.1.2
|
||||||
|
*/
|
||||||
|
public static Color randomColor() {
|
||||||
|
return randomColor(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成随机颜色
|
||||||
|
*
|
||||||
|
* @param random 随机对象 {@link Random}
|
||||||
|
* @return 随机颜色
|
||||||
|
* @since 3.1.2
|
||||||
|
*/
|
||||||
|
public static Color randomColor(Random random) {
|
||||||
|
if (null == random) {
|
||||||
|
random = RandomUtil.getRandom();
|
||||||
|
}
|
||||||
|
return new Color(random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取给定图片的主色调,背景填充用
|
||||||
|
*
|
||||||
|
* @param image {@link BufferedImage}
|
||||||
|
* @param rgbFilters 过滤多种颜色
|
||||||
|
* @return {@link String} #ffffff
|
||||||
|
* @since 5.6.7
|
||||||
|
*/
|
||||||
|
public static String getMainColor(BufferedImage image, int[]... rgbFilters) {
|
||||||
|
int r, g, b;
|
||||||
|
Map<String, Long> countMap = new HashMap<>();
|
||||||
|
int width = image.getWidth();
|
||||||
|
int height = image.getHeight();
|
||||||
|
int minx = image.getMinX();
|
||||||
|
int miny = image.getMinY();
|
||||||
|
for (int i = minx; i < width; i++) {
|
||||||
|
for (int j = miny; j < height; j++) {
|
||||||
|
int pixel = image.getRGB(i, j);
|
||||||
|
r = (pixel & 0xff0000) >> 16;
|
||||||
|
g = (pixel & 0xff00) >> 8;
|
||||||
|
b = (pixel & 0xff);
|
||||||
|
if (matchFilters(r, g, b, rgbFilters)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
countMap.merge(r + "-" + g + "-" + b, 1L, Long::sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String maxColor = null;
|
||||||
|
long maxCount = 0;
|
||||||
|
for (Map.Entry<String, Long> entry : countMap.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
Long count = entry.getValue();
|
||||||
|
if (count > maxCount) {
|
||||||
|
maxColor = key;
|
||||||
|
maxCount = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final String[] splitRgbStr = StrUtil.splitToArray(maxColor, '-');
|
||||||
|
String rHex = Integer.toHexString(Integer.parseInt(splitRgbStr[0]));
|
||||||
|
String gHex = Integer.toHexString(Integer.parseInt(splitRgbStr[1]));
|
||||||
|
String bHex = Integer.toHexString(Integer.parseInt(splitRgbStr[2]));
|
||||||
|
rHex = rHex.length() == 1 ? "0" + rHex : rHex;
|
||||||
|
gHex = gHex.length() == 1 ? "0" + gHex : gHex;
|
||||||
|
bHex = bHex.length() == 1 ? "0" + bHex : bHex;
|
||||||
|
return "#" + rHex + gHex + bHex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 给定RGB是否匹配过滤器中任何一个RGB颜色
|
||||||
|
*
|
||||||
|
* @param r R
|
||||||
|
* @param g G
|
||||||
|
* @param b B
|
||||||
|
* @param rgbFilters 颜色过滤器
|
||||||
|
* @return 是否匹配
|
||||||
|
*/
|
||||||
|
private static boolean matchFilters(int r, int g, int b, int[]... rgbFilters) {
|
||||||
|
if (rgbFilters != null && rgbFilters.length > 0) {
|
||||||
|
for (int[] rgbFilter : rgbFilters) {
|
||||||
|
if (r == rgbFilter[0] && g == rgbFilter[1] && b == rgbFilter[2]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,13 @@
|
|||||||
package cn.hutool.core.img;
|
package cn.hutool.core.img;
|
||||||
|
|
||||||
import cn.hutool.core.codec.Base64;
|
import cn.hutool.core.codec.Base64;
|
||||||
import cn.hutool.core.convert.Convert;
|
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.io.IORuntimeException;
|
import cn.hutool.core.io.IORuntimeException;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.io.resource.Resource;
|
import cn.hutool.core.io.resource.Resource;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
|
||||||
import cn.hutool.core.util.NumberUtil;
|
import cn.hutool.core.util.NumberUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.core.util.URLUtil;
|
import cn.hutool.core.util.URLUtil;
|
||||||
|
|
||||||
@ -23,7 +20,18 @@ import javax.imageio.ImageWriter;
|
|||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import java.awt.*;
|
import java.awt.Color;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.GraphicsConfiguration;
|
||||||
|
import java.awt.GraphicsDevice;
|
||||||
|
import java.awt.GraphicsEnvironment;
|
||||||
|
import java.awt.HeadlessException;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.Toolkit;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.font.FontRenderContext;
|
import java.awt.font.FontRenderContext;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
@ -43,10 +51,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,12 +70,6 @@ public class ImgUtil {
|
|||||||
public static final String IMAGE_TYPE_PNG = "png";// 可移植网络图形
|
public static final String IMAGE_TYPE_PNG = "png";// 可移植网络图形
|
||||||
public static final String IMAGE_TYPE_PSD = "psd";// Photoshop的专用格式Photoshop
|
public static final String IMAGE_TYPE_PSD = "psd";// Photoshop的专用格式Photoshop
|
||||||
|
|
||||||
/**
|
|
||||||
* RGB颜色范围上限
|
|
||||||
*/
|
|
||||||
private static final int RGB_COLOR_BOUND = 256;
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------- scale
|
// ---------------------------------------------------------------------------------------------------------------------- scale
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1964,10 +1963,11 @@ public class ImgUtil {
|
|||||||
*
|
*
|
||||||
* @param color {@link Color}
|
* @param color {@link Color}
|
||||||
* @return 16进制的颜色值,例如#fcf6d6
|
* @return 16进制的颜色值,例如#fcf6d6
|
||||||
|
* @see ColorUtil#toHex(Color)
|
||||||
* @since 4.1.14
|
* @since 4.1.14
|
||||||
*/
|
*/
|
||||||
public static String toHex(Color color) {
|
public static String toHex(Color color) {
|
||||||
return toHex(color.getRed(), color.getGreen(), color.getBlue());
|
return ColorUtil.toHex(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1976,14 +1976,11 @@ public class ImgUtil {
|
|||||||
* @param r 红(R)
|
* @param r 红(R)
|
||||||
* @param g 绿(G)
|
* @param g 绿(G)
|
||||||
* @param b 蓝(B)
|
* @param b 蓝(B)
|
||||||
* @return 返回字符串形式的 十六进制颜色码 如
|
* @return 返回字符串形式的 十六进制颜色码
|
||||||
|
* @see ColorUtil#toHex(int, int, int)
|
||||||
*/
|
*/
|
||||||
public static String toHex(int r, int g, int b) {
|
public static String toHex(int r, int g, int b) {
|
||||||
// rgb 小于 255
|
return ColorUtil.toHex(r, g, b);
|
||||||
if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) {
|
|
||||||
throw new IllegalArgumentException("RGB must be 0~255!");
|
|
||||||
}
|
|
||||||
return String.format("#%02X%02X%02X", r, g, b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1994,7 +1991,7 @@ public class ImgUtil {
|
|||||||
* @since 4.1.14
|
* @since 4.1.14
|
||||||
*/
|
*/
|
||||||
public static Color hexToColor(String hex) {
|
public static Color hexToColor(String hex) {
|
||||||
return getColor(Integer.parseInt(StrUtil.removePrefix(hex, "#"), 16));
|
return ColorUtil.hexToColor(hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2002,10 +1999,11 @@ public class ImgUtil {
|
|||||||
*
|
*
|
||||||
* @param rgb RGB值
|
* @param rgb RGB值
|
||||||
* @return {@link Color}
|
* @return {@link Color}
|
||||||
|
* @see ColorUtil#getColor(int)
|
||||||
* @since 4.1.14
|
* @since 4.1.14
|
||||||
*/
|
*/
|
||||||
public static Color getColor(int rgb) {
|
public static Color getColor(int rgb) {
|
||||||
return new Color(rgb);
|
return ColorUtil.getColor(rgb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2021,76 +2019,22 @@ public class ImgUtil {
|
|||||||
*
|
*
|
||||||
* @param colorName 颜色的英文名,16进制表示或RGB表示
|
* @param colorName 颜色的英文名,16进制表示或RGB表示
|
||||||
* @return {@link Color}
|
* @return {@link Color}
|
||||||
|
* @see ColorUtil#getColor(String)
|
||||||
* @since 4.1.14
|
* @since 4.1.14
|
||||||
*/
|
*/
|
||||||
public static Color getColor(String colorName) {
|
public static Color getColor(String colorName) {
|
||||||
if (StrUtil.isBlank(colorName)) {
|
return ColorUtil.getColor(colorName);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
colorName = colorName.toUpperCase();
|
|
||||||
|
|
||||||
if ("BLACK".equals(colorName)) {
|
|
||||||
return Color.BLACK;
|
|
||||||
} else if ("WHITE".equals(colorName)) {
|
|
||||||
return Color.WHITE;
|
|
||||||
} else if ("LIGHTGRAY".equals(colorName) || "LIGHT_GRAY".equals(colorName)) {
|
|
||||||
return Color.LIGHT_GRAY;
|
|
||||||
} else if ("GRAY".equals(colorName)) {
|
|
||||||
return Color.GRAY;
|
|
||||||
} else if ("DARKGRAY".equals(colorName) || "DARK_GRAY".equals(colorName)) {
|
|
||||||
return Color.DARK_GRAY;
|
|
||||||
} else if ("RED".equals(colorName)) {
|
|
||||||
return Color.RED;
|
|
||||||
} else if ("PINK".equals(colorName)) {
|
|
||||||
return Color.PINK;
|
|
||||||
} else if ("ORANGE".equals(colorName)) {
|
|
||||||
return Color.ORANGE;
|
|
||||||
} else if ("YELLOW".equals(colorName)) {
|
|
||||||
return Color.YELLOW;
|
|
||||||
} else if ("GREEN".equals(colorName)) {
|
|
||||||
return Color.GREEN;
|
|
||||||
} else if ("MAGENTA".equals(colorName)) {
|
|
||||||
return Color.MAGENTA;
|
|
||||||
} else if ("CYAN".equals(colorName)) {
|
|
||||||
return Color.CYAN;
|
|
||||||
} else if ("BLUE".equals(colorName)) {
|
|
||||||
return Color.BLUE;
|
|
||||||
} else if ("DARKGOLD".equals(colorName)) {
|
|
||||||
// 暗金色
|
|
||||||
return hexToColor("#9e7e67");
|
|
||||||
} else if ("LIGHTGOLD".equals(colorName)) {
|
|
||||||
// 亮金色
|
|
||||||
return hexToColor("#ac9c85");
|
|
||||||
} else if (StrUtil.startWith(colorName, '#')) {
|
|
||||||
return hexToColor(colorName);
|
|
||||||
} else if (StrUtil.startWith(colorName, '$')) {
|
|
||||||
// 由于#在URL传输中无法传输,因此用$代替#
|
|
||||||
return hexToColor("#" + colorName.substring(1));
|
|
||||||
} else {
|
|
||||||
// rgb值
|
|
||||||
final List<String> rgb = StrUtil.split(colorName, ',');
|
|
||||||
if (3 == rgb.size()) {
|
|
||||||
final Integer r = Convert.toInt(rgb.get(0));
|
|
||||||
final Integer g = Convert.toInt(rgb.get(1));
|
|
||||||
final Integer b = Convert.toInt(rgb.get(2));
|
|
||||||
if (false == ArrayUtil.hasNull(r, g, b)) {
|
|
||||||
return new Color(r, g, b);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成随机颜色
|
* 生成随机颜色
|
||||||
*
|
*
|
||||||
* @return 随机颜色
|
* @return 随机颜色
|
||||||
|
* @see ColorUtil#randomColor()
|
||||||
* @since 3.1.2
|
* @since 3.1.2
|
||||||
*/
|
*/
|
||||||
public static Color randomColor() {
|
public static Color randomColor() {
|
||||||
return randomColor(null);
|
return ColorUtil.randomColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2098,13 +2042,11 @@ public class ImgUtil {
|
|||||||
*
|
*
|
||||||
* @param random 随机对象 {@link Random}
|
* @param random 随机对象 {@link Random}
|
||||||
* @return 随机颜色
|
* @return 随机颜色
|
||||||
|
* @see ColorUtil#randomColor(Random)
|
||||||
* @since 3.1.2
|
* @since 3.1.2
|
||||||
*/
|
*/
|
||||||
public static Color randomColor(Random random) {
|
public static Color randomColor(Random random) {
|
||||||
if (null == random) {
|
return ColorUtil.randomColor(random);
|
||||||
random = RandomUtil.getRandom();
|
|
||||||
}
|
|
||||||
return new Color(random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2129,66 +2071,12 @@ public class ImgUtil {
|
|||||||
* @param image {@link BufferedImage}
|
* @param image {@link BufferedImage}
|
||||||
* @param rgbFilters 过滤多种颜色
|
* @param rgbFilters 过滤多种颜色
|
||||||
* @return {@link String} #ffffff
|
* @return {@link String} #ffffff
|
||||||
|
* @see ColorUtil#getMainColor(BufferedImage, int[]...)
|
||||||
* @since 5.6.7
|
* @since 5.6.7
|
||||||
*/
|
*/
|
||||||
public static String getMainColor(BufferedImage image, int[]... rgbFilters) {
|
public static String getMainColor(BufferedImage image, int[]... rgbFilters) {
|
||||||
int r, g, b;
|
return ColorUtil.getMainColor(image, rgbFilters);
|
||||||
Map<String, Long> countMap = new HashMap<>();
|
|
||||||
int width = image.getWidth();
|
|
||||||
int height = image.getHeight();
|
|
||||||
int minx = image.getMinX();
|
|
||||||
int miny = image.getMinY();
|
|
||||||
for (int i = minx; i < width; i++) {
|
|
||||||
for (int j = miny; j < height; j++) {
|
|
||||||
int pixel = image.getRGB(i, j);
|
|
||||||
r = (pixel & 0xff0000) >> 16;
|
|
||||||
g = (pixel & 0xff00) >> 8;
|
|
||||||
b = (pixel & 0xff);
|
|
||||||
if(matchFilters(r, g, b, rgbFilters)){
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
countMap.merge(r + "-" + g + "-" + b, 1L, Long::sum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String maxColor = null;
|
|
||||||
long maxCount = 0;
|
|
||||||
for (Map.Entry<String, Long> entry : countMap.entrySet()) {
|
|
||||||
String key = entry.getKey();
|
|
||||||
Long count = entry.getValue();
|
|
||||||
if (count > maxCount) {
|
|
||||||
maxColor = key;
|
|
||||||
maxCount = count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final String[] splitRgbStr = StrUtil.splitToArray(maxColor, '-');
|
|
||||||
String rHex = Integer.toHexString(Integer.parseInt(splitRgbStr[0]));
|
|
||||||
String gHex = Integer.toHexString(Integer.parseInt(splitRgbStr[1]));
|
|
||||||
String bHex = Integer.toHexString(Integer.parseInt(splitRgbStr[2]));
|
|
||||||
rHex = rHex.length() == 1 ? "0" + rHex : rHex;
|
|
||||||
gHex = gHex.length() == 1 ? "0" + gHex : gHex;
|
|
||||||
bHex = bHex.length() == 1 ? "0" + bHex : bHex;
|
|
||||||
return "#" + rHex + gHex + bHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 给定RGB是否匹配过滤器中任何一个RGB颜色
|
|
||||||
* @param r R
|
|
||||||
* @param g G
|
|
||||||
* @param b B
|
|
||||||
* @param rgbFilters 颜色过滤器
|
|
||||||
* @return 是否匹配
|
|
||||||
*/
|
|
||||||
private static boolean matchFilters(int r, int g, int b, int[]... rgbFilters){
|
|
||||||
if (rgbFilters != null && rgbFilters.length > 0) {
|
|
||||||
for (int[] rgbFilter : rgbFilters) {
|
|
||||||
if (r == rgbFilter[0] && g == rgbFilter[1] && b == rgbFilter[2]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------------ 背景图换算
|
// ------------------------------------------------------------------------------------------------------ 背景图换算
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
90
hutool-core/src/main/java/cn/hutool/core/img/LabColor.java
Normal file
90
hutool-core/src/main/java/cn/hutool/core/img/LabColor.java
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package cn.hutool.core.img;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.color.ColorSpace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表示以 LAB 形式存储的颜色。<br>
|
||||||
|
* <ul>
|
||||||
|
* <li>L: 亮度</li>
|
||||||
|
* <li>a: 正数代表红色,负端代表绿色</li>
|
||||||
|
* <li>b: 正数代表黄色,负端代表蓝色</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author Tom Xin
|
||||||
|
* @since 5.8.7
|
||||||
|
*/
|
||||||
|
public class LabColor {
|
||||||
|
|
||||||
|
private static final ColorSpace XYZ_COLOR_SPACE = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* L: 亮度
|
||||||
|
*/
|
||||||
|
private final double l;
|
||||||
|
/**
|
||||||
|
* A: 正数代表红色,负端代表绿色
|
||||||
|
*/
|
||||||
|
private final double a;
|
||||||
|
/**
|
||||||
|
* B: 正数代表黄色,负端代表蓝色
|
||||||
|
*/
|
||||||
|
private final double b;
|
||||||
|
|
||||||
|
public LabColor(Integer rgb) {
|
||||||
|
this((rgb != null) ? new Color(rgb) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LabColor(Color color) {
|
||||||
|
Assert.notNull(color, "Color must not be null");
|
||||||
|
final float[] lab = fromXyz(color.getColorComponents(XYZ_COLOR_SPACE, null));
|
||||||
|
this.l = lab[0];
|
||||||
|
this.a = lab[1];
|
||||||
|
this.b = lab[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取颜色差
|
||||||
|
* @param other 其他Lab颜色
|
||||||
|
* @return 颜色差
|
||||||
|
*/
|
||||||
|
// See https://en.wikipedia.org/wiki/Color_difference#CIE94
|
||||||
|
public double getDistance(LabColor other) {
|
||||||
|
double c1 = Math.sqrt(this.a * this.a + this.b * this.b);
|
||||||
|
double deltaC = c1 - Math.sqrt(other.a * other.a + other.b * other.b);
|
||||||
|
double deltaA = this.a - other.a;
|
||||||
|
double deltaB = this.b - other.b;
|
||||||
|
double deltaH = Math.sqrt(Math.max(0.0, deltaA * deltaA + deltaB * deltaB - deltaC * deltaC));
|
||||||
|
return Math.sqrt(Math.max(0.0, Math.pow((this.l - other.l), 2)
|
||||||
|
+ Math.pow(deltaC / (1 + 0.045 * c1), 2) + Math.pow(deltaH / (1 + 0.015 * c1), 2.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private float[] fromXyz(float[] xyz) {
|
||||||
|
return fromXyz(xyz[0], xyz[1], xyz[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从xyz换算<br>
|
||||||
|
* L=116f(y)-16<br>
|
||||||
|
* a=500[f(x/0.982)-f(y)]<br>
|
||||||
|
* b=200[f(y)-f(z/1.183 )]<br>
|
||||||
|
* 其中: f(x)=7.787x+0.138, x<0.008856; f(x)=(x)1/3,x>0.008856
|
||||||
|
*
|
||||||
|
* @param x X
|
||||||
|
* @param y Y
|
||||||
|
* @param z Z
|
||||||
|
* @return Lab
|
||||||
|
*/
|
||||||
|
private static float[] fromXyz(float x, float y, float z) {
|
||||||
|
final double l = (f(y) - 16.0) * 116.0;
|
||||||
|
final double a = (f(x) - f(y)) * 500.0;
|
||||||
|
final double b = (f(y) - f(z)) * 200.0;
|
||||||
|
return new float[]{(float) l, (float) a, (float) b};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double f(double t) {
|
||||||
|
return (t > (216.0 / 24389.0)) ? Math.cbrt(t) : (1.0 / 3.0) * Math.pow(29.0 / 6.0, 2) * t + (4.0 / 29.0);
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,8 @@
|
|||||||
package cn.hutool.core.lang.ansi;
|
package cn.hutool.core.lang.ansi;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.img.LabColor;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.color.ColorSpace;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -117,59 +116,6 @@ public final class AnsiColors {
|
|||||||
return closest;
|
return closest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 表示以 LAB 形式存储的颜色。
|
|
||||||
*/
|
|
||||||
private static final class LabColor {
|
|
||||||
|
|
||||||
private static final ColorSpace XYZ_COLOR_SPACE = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
|
|
||||||
|
|
||||||
private final double l;
|
|
||||||
|
|
||||||
private final double a;
|
|
||||||
|
|
||||||
private final double b;
|
|
||||||
|
|
||||||
LabColor(Integer rgb) {
|
|
||||||
this((rgb != null) ? new Color(rgb) : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
LabColor(Color color) {
|
|
||||||
Assert.notNull(color, "Color must not be null");
|
|
||||||
float[] lab = fromXyz(color.getColorComponents(XYZ_COLOR_SPACE, null));
|
|
||||||
this.l = lab[0];
|
|
||||||
this.a = lab[1];
|
|
||||||
this.b = lab[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
private float[] fromXyz(float[] xyz) {
|
|
||||||
return fromXyz(xyz[0], xyz[1], xyz[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private float[] fromXyz(float x, float y, float z) {
|
|
||||||
double l = (f(y) - 16.0) * 116.0;
|
|
||||||
double a = (f(x) - f(y)) * 500.0;
|
|
||||||
double b = (f(y) - f(z)) * 200.0;
|
|
||||||
return new float[] { (float) l, (float) a, (float) b };
|
|
||||||
}
|
|
||||||
|
|
||||||
private double f(double t) {
|
|
||||||
return (t > (216.0 / 24389.0)) ? Math.cbrt(t) : (1.0 / 3.0) * Math.pow(29.0 / 6.0, 2) * t + (4.0 / 29.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// See https://en.wikipedia.org/wiki/Color_difference#CIE94
|
|
||||||
double getDistance(LabColor other) {
|
|
||||||
double c1 = Math.sqrt(this.a * this.a + this.b * this.b);
|
|
||||||
double deltaC = c1 - Math.sqrt(other.a * other.a + other.b * other.b);
|
|
||||||
double deltaA = this.a - other.a;
|
|
||||||
double deltaB = this.b - other.b;
|
|
||||||
double deltaH = Math.sqrt(Math.max(0.0, deltaA * deltaA + deltaB * deltaB - deltaC * deltaC));
|
|
||||||
return Math.sqrt(Math.max(0.0, Math.pow((this.l - other.l), 2)
|
|
||||||
+ Math.pow(deltaC / (1 + 0.045 * c1), 2) + Math.pow(deltaH / (1 + 0.015 * c1), 2.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 此类支持的位深度。
|
* 此类支持的位深度。
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user