我们经常会看看钉钉这个办公软件,如果你没有传头像上去,他会默认生成一个带有你的名字的头像,这个是怎么生成的呢,有很多需求里面可能也会有 这个要求,就是通过一个名词生成一个头像,接下来我和大家说一下具体思路。
1、你先拿到那个名称,如果是名字,三个字或者两个字,你只需要对应的切割一下就好,生成一个标识,如果是公司名称可能就会比较复杂,因为公司名称包含地市标识,还有什么有限公司,科技有限 公司等结尾,我们需要把这个给切割掉,所以需要费一点功夫,后面我在代码里面会进行注释。
2、随机选取 一种颜色,最好排除背景和字体 是同一种颜色或者是很相近的颜色,这样会影响查看,通过颜色生成一张一定大小的的纯色图片,然后将你的标识(切割后的名称)放在图片中间就好,这样就可以生成一张图片了,效果图类似于这样的
然后下面来看代码,代码就 不讲解了,我会尽可能的注释清楚
package com.yz.robot.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Map;
import java.util.List;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
/**
* @author yanming.gu
* @ClassName: CreateNamePictureUtils
* @Description 通过名称生成企业头像的工具类, 带有企业的名称标识
* @since 1.0
*/
public class CreateNamePictureUtils {
private final static Logger logger = Logger.getLogger(CreateNamePictureUtils.class);
/**
* @throws IOException
* @throws
**/
public static void main(String[] args) throws IOException {
String name = "杭州娃哈哈科技有限公司";
String headImage = generateImageAndUploadOss(name, 100, 100, 0);
System.out.println(headImage);
}
public static String generateImageAndUploadOss(String name){
// 获取关键字
String jsonStr = getKeyName(name);
int abs = Math.abs(name.hashCode());
try {
logger.info("生成头像开始》》》》》》");
byte[] bytes = generateImg(jsonStr, 100, 100, 0);
// 下面这一步是吧文件传到oss上面去,这个工具类是自己写的,你需要替换,传到你们自己的
服务器上去。返回的是图片的访问路径
String headImage = AliOssUtil.upload(abs + ".jpg", bytes);
logger.info("生成头像结束》》》》》》");
logger.info("生成头像的路径为:"+ headImage);
return headImage;
} catch (IOException e) {
logger.error("生成头像失败》》》》》》");
logger.error(e.getMessage());
}
return "";
}
public static String generateImageAndUploadOss(String name, int width, int height, int cornerRadius){
// 获取关键字
String jsonStr = getKeyName(name);
int abs = Math.abs(name.hashCode());
try {
logger.info("生成头像开始》》》》》》");
byte[] bytes = generateImg(jsonStr, width, height, cornerRadius);
// 下面这一步是吧文件传到oss上面去,这个工具类是自己写的,你需要替换,传到你们自己的
服务器上去。返回的是图片的访问路径
String headImage = AliOssUtil.upload(abs + ".jpg", bytes);
logger.info("生成头像结束》》》》》》");
logger.info("生成头像的路径为:"+ headImage);
return headImage;
} catch (IOException e) {
logger.error("生成头像失败》》》》》》");
logger.error(e.getMessage());
}
return "";
}
public static String generateImageAndUploadOss(String name, int width, int height){
// 获取关键字
String jsonStr = getKeyName(name);
int abs = Math.abs(name.hashCode());
try {
logger.info("生成头像开始》》》》》》");
byte[] bytes = generateImg(jsonStr, width, height, 0);
// 下面这一步是吧文件传到oss上面去,这个工具类是自己写的,你需要替换,传到你们自己的
服务器上去。返回的是图片的访问路径
String headImage = AliOssUtil.upload(abs + ".jpg", bytes);
logger.info("生成头像结束》》》》》》");
logger.info("生成头像的路径为:"+ headImage);
return headImage;
} catch (IOException e) {
logger.error("生成头像失败》》》》》》");
logger.error(e.getMessage());
}
return "";
}
// 获取关键字,也就是对传过来的的名称进行切割
public static String getKeyName(String name){
int length = name.length();
//如果用户输入的姓名少于等于2个字符,不用截取
if (name.length() <= 2) {
return name;
} else if (name.length() <= 4) {
//如果用户输入的姓名大于等于3个字符,截取后面两位
String first = name.substring(0, 1);
if (isChinese(first)) {
//截取倒数两位汉字
name = name.substring(length - 2);
} else {
//截取前面的两个英文字母
name = name.substring(0, 2).toUpperCase();
}
return name;
}
// 读取json文件的数据,生成json列表
InputStream resourceAsStream = CreateNamePictureUtils.class.getResourceAsStream("/cityAndcompanySuffixes.json");
String jsonStr = readJsonFile(resourceAsStream);
Map jsonMap = (Map) JSON.parse(jsonStr);
JSONArray cities = (JSONArray)jsonMap.get("cities");
JSONArray companySuffixes = (JSONArray)jsonMap.get("company_suffixes");
List nameList = new ArrayList();
for (int i = 0, len = cities.size(); i < len; i++) {
String prefix = cities.getString(i);
if (StringUtils.startsWith(name, prefix)) {
String nameSub = name.substring(prefix.length());
nameList.add(nameSub);
}
}
name = getStrLenShort(nameList, name);
List nameList2 = new ArrayList();
for (int i = 0, len = companySuffixes.size(); i < len; i++) {
String suffix = companySuffixes.getString(i);
if (StringUtils.endsWith(name, suffix)) {
String substring = name.substring(0, (name.length() - suffix.length()));
nameList2.add(substring);
}
}
name = getStrLenShort(nameList2, name);
return name;
}
/**
* 获取list中最短的字符串
*/
public static String getStrLenShort(List nameList, String name){
if(nameList.size() > 0) {
String tempName = nameList.get(0);
String temp = "";
for(int i = 1, len = nameList.size(); i < len; i++) {
temp = nameList.get(i);
if(tempName.length() > temp.length()) {
tempName = temp;
}
}
name = tempName;
}
return name;
}
/**
* 读取json文件,这个主要是因为如果是企业名称的话需要去掉地市和一些后缀
* @param resourceAsStream
* @return 返回json字符串
*/
public static String readJsonFile(InputStream resourceAsStream) {
String jsonStr = "";
logger.info("————开始读取文件————");
try {
Reader reader = new InputStreamReader(resourceAsStream, "utf-8");
int ch = 0;
StringBuffer sb = new StringBuffer();
while ((ch = reader.read()) != -1) {
sb.append((char) ch);
}
reader.close();
jsonStr = sb.toString();
logger.info("————读取文件结束!————");
return jsonStr;
} catch (Exception e) {
logger.info("————读取文件出现异常,读取失败!————");
e.printStackTrace();
return null;
}
}
/**
* 绘制字体头像 输入到本地
* @param name
* @param outputPath 文件输出到本地的路径
* @param outputName 文件输出到本地的名称
* @param width 图片宽度
* @param height 图片高度
* @param cornerRadius 锐化值,锐化值越大,生成的图片趋于圆
* @throws IOException
*/
public static void generateImg(String name, String outputPath, String outputName, int width, int height, int cornerRadius)
throws IOException {
String filename = outputPath + File.separator + outputName + ".jpg";
File file = new File(filename);
BufferedImage rounded = commonGenerateImg(name, width, height, 0);
ImageIO.write(rounded, "png", file);
}
/**
* 绘制字体头像 生成二进制数组
* 如果是英文名,只显示首字母大写
* 如果是中文名,只显示最后两个字
* @param name 放到图片中的名称
* @param width 图片宽度
* @param height 图片高度
* @param cornerRadius 锐化值,锐化值越大,生成的图片趋于圆
* @throws IOException
*/
public static byte[] generateImg(String name, int width, int height, int cornerRadius)
throws IOException {
BufferedImage rounded = commonGenerateImg(name, width, height, 0);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(rounded, "png", byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
/**
* 绘制字体头像
* 如果是英文名,只显示首字母大写
* 如果是中文名,只显示最后两个字
* @param name 放到图片中的名称
* @param width 图片宽度
* @param height 图片高度
* @param cornerRadius 锐化值,锐化值越大,生成的图片趋于圆
* @return
*/
public static BufferedImage commonGenerateImg(String name, int width, int height, int cornerRadius){
int nameLen = name.length();
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D) bi.getGraphics();
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setBackground(getRandomColor());
g2.clearRect(0, 0, width, height);
Font font = null;
//两个字及以上
if(name.length() >= 2) {
font = new Font("微软雅黑", Font.PLAIN, 20);
g2.setFont(font);
String firstWritten = name.substring(0, 1);
String secondWritten = name.substring(1, 2);
//两个中文 如 言曌
if (isChinese(firstWritten) && isChinese(secondWritten)) {
//文字居中
FontMetrics fm = g2.getFontMetrics();
//画出水印
g2.drawString(name,(width - fm.stringWidth(name))/2, (height/2 +5));
}
//首中次英 如 罗Q
else if (isChinese(firstWritten) && !isChinese(secondWritten)) {
//文字居中
FontMetrics fm = g2.getFontMetrics();
//画出水印
g2.drawString(name,(width - fm.stringWidth(name))/2, (height/2 +5));
} else {
//首英,如 AB
name = name.substring(0,1);
}
}
//一个字
if(name.length() ==1) {
// 中文
if(isChinese(name)) {
font = new Font("微软雅黑", Font.PLAIN, 20);
g2.setFont(font);
//文字居中
FontMetrics fm = g2.getFontMetrics();
//画出水印
g2.drawString(name,(width - fm.stringWidth(name))/2, (height/2 +5));
} else {
// 英文
font = new Font("微软雅黑", Font.PLAIN, 20);
g2.setFont(font);
//文字居中
FontMetrics fm = g2.getFontMetrics();
//画出水印
g2.drawString(name,(width - fm.stringWidth(name))/2, (height/2 + 5));
}
}
BufferedImage rounded = makeRoundedCorner(bi, cornerRadius);
return rounded;
}
/**
* 判断字符串是否为中文
* @param str
* @return
*/
public static boolean isChinese(String str) {
String regEx = "[\\u4e00-\\u9fa5]+";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);
if (m.find())
return true;
else
return false;
}
/**
* 获得随机颜色
* @return
*/
private static Color getRandomColor() {
String[] beautifulColors =
new String[]{"232,221,203", "205,179,128", "3,101,100", "3,54,73", "3,22,52", "237,222,139", "251,178,23", "96,143,159", "1,77,103", "254,67,101", "252,157,154","249,205,173", "200,200,169", "131,175,155", "229,187,129", "161,23,21", "34,8,7","118,77,57", "17,63,61", "60,79,57", "95,92,51", "179,214,110", "248,147,29", "227,160,93", "178,190,126", "114,111,238", "56,13,49", "89,61,67", "250,218,141", "3,38,58", "179,168,150", "222,125,44", "20,68,106", "130,57,53", "137,190,178", "201,186,131", "222,211,140", "222,156,83", "23,44,60", "39,72,98", "153,80,84", "217,104,49", "230,179,61", "174,221,129", "107,194,53", "6,128,67", "38,157,128", "178,200,187", "69,137,148", "117,121,71", "114,83,52", "87,105,60", "82,75,46", "171,92,37", "100,107,48", "98,65,24", "54,37,17", "137,157,192", "250,227,113", "29,131,8", "220,87,18", "29,191,151", "35,235,185", "213,26,33", "160,191,124", "101,147,74", "64,116,52", "255,150,128", "255,94,72", "38,188,213", "167,220,224", "1,165,175", "179,214,110", "248,147,29", "230,155,3", "209,73,78", "62,188,202", "224,160,158", "161,47,47", "0,90,171", "107,194,53", "174,221,129", "6,128,67", "38,157,128", "201,138,131", "220,162,151", "137,157,192", "175,215,237", "92,167,186", "255,66,93", "147,224,255", "247,68,97", "185,227,217"};
int len = beautifulColors.length;
Random random = new Random();
String[] color = beautifulColors[random.nextInt(len)].split(",");
return new Color(Integer.parseInt(color[0]), Integer.parseInt(color[1]),
Integer.parseInt(color[2]));
}
/**
* 图片做圆角处理
* @param image
* @param cornerRadius
* @return
*/
public static BufferedImage makeRoundedCorner(BufferedImage image, int cornerRadius) {
int w = image.getWidth();
int h = image.getHeight();
BufferedImage output = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = output.createGraphics();
g2.setComposite(AlphaComposite.Src);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.WHITE);
g2.fill(new RoundRectangle2D.Float(0, 0, w, h, cornerRadius, cornerRadius));
g2.setComposite(AlphaComposite.SrcAtop);
g2.drawImage(image, 0, 0, null);
g2.dispose();
return output;
}
}
还有一个json文件cityAndcompanySuffixes.json,放在resources更目录下面,内容你可以自己去维护 ,下面是小编维护的,这个json文件只针对于企业名称,如果你需要生成其他方面的头像,需要你自己去维护一个,然后修改对应的值。
{
"cities":[
"呼和浩特市",
"鄂尔多斯市",
"呼伦贝尔市",
"巴彦淖尔市",
"乌兰察布市",
"齐齐哈尔市",
"乌鲁木齐市",
"克拉玛依市",
"石家庄市",
"秦皇岛市",
"张家口市",
"呼和浩特",
"鄂尔多斯",
"呼伦贝尔",
"巴彦淖尔",
"乌兰察布",
"葫芦岛市",
"哈尔滨市",
"齐齐哈尔",
"双鸭山市",
"佳木斯市",
"七台河市",
"牡丹江市",
"连云港市",
"马鞍山市",
"景德镇市",
"平顶山市",
"三门峡市",
"驻马店市",
"张家界市",
"防城港市",
"攀枝花市",
"六盘水市",
"日喀则市",
"嘉峪关市",
"石嘴山市",
"乌鲁木齐",
"克拉玛依",
"吐鲁番市",
"北京市",
"天津市",
"石家庄",
"唐山市",
"秦皇岛",
"邯郸市",
"邢台市",
"保定市",
"张家口",
"承德市",
"沧州市",
"廊坊市",
"衡水市",
"太原市",
"大同市",
"阳泉市",
"长治市",
"晋城市",
"朔州市",
"晋中市",
"运城市",
"忻州市",
"临汾市",
"吕梁市",
"包头市",
"乌海市",
"赤峰市",
"通辽市",
"沈阳市",
"大连市",
"鞍山市",
"抚顺市",
"本溪市",
"丹东市",
"锦州市",
"营口市",
"阜新市",
"辽阳市",
"盘锦市",
"铁岭市",
"朝阳市",
"葫芦岛",
"长春市",
"吉林市",
"四平市",
"辽源市",
"通化市",
"白山市",
"松原市",
"白城市",
"哈尔滨",
"鸡西市",
"鹤岗市",
"双鸭山",
"大庆市",
"伊春市",
"佳木斯",
"七台河",
"牡丹江",
"黑河市",
"绥化市",
"上海市",
"南京市",
"无锡市",
"徐州市",
"常州市",
"苏州市",
"南通市",
"连云港",
"淮安市",
"盐城市",
"扬州市",
"镇江市",
"泰州市",
"宿迁市",
"杭州市",
"宁波市",
"温州市",
"嘉兴市",
"湖州市",
"绍兴市",
"金华市",
"衢州市",
"舟山市",
"台州市",
"丽水市",
"合肥市",
"芜湖市",
"蚌埠市",
"淮南市",
"马鞍山",
"淮北市",
"铜陵市",
"安庆市",
"黄山市",
"滁州市",
"阜阳市",
"宿州市",
"六安市",
"亳州市",
"池州市",
"宣城市",
"福州市",
"厦门市",
"莆田市",
"三明市",
"泉州市",
"漳州市",
"南平市",
"龙岩市",
"宁德市",
"南昌市",
"景德镇",
"萍乡市",
"九江市",
"新余市",
"鹰潭市",
"赣州市",
"吉安市",
"宜春市",
"抚州市",
"上饶市",
"济南市",
"青岛市",
"淄博市",
"枣庄市",
"东营市",
"烟台市",
"潍坊市",
"济宁市",
"泰安市",
"威海市",
"日照市",
"临沂市",
"德州市",
"聊城市",
"滨州市",
"菏泽市",
"郑州市",
"开封市",
"洛阳市",
"平顶山",
"安阳市",
"鹤壁市",
"新乡市",
"焦作市",
"濮阳市",
"许昌市",
"漯河市",
"三门峡",
"南阳市",
"商丘市",
"信阳市",
"周口市",
"驻马店",
"武汉市",
"黄石市",
"十堰市",
"宜昌市",
"襄阳市",
"鄂州市",
"荆门市",
"孝感市",
"荆州市",
"黄冈市",
"咸宁市",
"随州市",
"长沙市",
"株洲市",
"湘潭市",
"衡阳市",
"邵阳市",
"岳阳市",
"常德市",
"张家界",
"益阳市",
"郴州市",
"永州市",
"怀化市",
"娄底市",
"广州市",
"韶关市",
"深圳市",
"珠海市",
"汕头市",
"佛山市",
"江门市",
"湛江市",
"茂名市",
"肇庆市",
"惠州市",
"梅州市",
"汕尾市",
"河源市",
"阳江市",
"清远市",
"东莞市",
"中山市",
"潮州市",
"揭阳市",
"云浮市",
"南宁市",
"柳州市",
"桂林市",
"梧州市",
"北海市",
"防城港",
"钦州市",
"贵港市",
"玉林市",
"百色市",
"贺州市",
"河池市",
"来宾市",
"崇左市",
"海口市",
"三亚市",
"三沙市",
"儋州市",
"重庆市",
"成都市",
"自贡市",
"攀枝花",
"泸州市",
"德阳市",
"绵阳市",
"广元市",
"遂宁市",
"内江市",
"乐山市",
"南充市",
"眉山市",
"宜宾市",
"广安市",
"达州市",
"雅安市",
"巴中市",
"资阳市",
"贵阳市",
"六盘水",
"遵义市",
"安顺市",
"毕节市",
"铜仁市",
"昆明市",
"曲靖市",
"玉溪市",
"保山市",
"昭通市",
"丽江市",
"普洱市",
"临沧市",
"拉萨市",
"日喀则",
"昌都市",
"林芝市",
"山南市",
"那曲市",
"西安市",
"铜川市",
"宝鸡市",
"咸阳市",
"渭南市",
"延安市",
"汉中市",
"榆林市",
"安康市",
"商洛市",
"兰州市",
"嘉峪关",
"金昌市",
"白银市",
"天水市",
"武威市",
"张掖市",
"平凉市",
"酒泉市",
"庆阳市",
"定西市",
"陇南市",
"西宁市",
"海东市",
"银川市",
"石嘴山",
"吴忠市",
"固原市",
"中卫市",
"吐鲁番",
"哈密市",
"北京",
"天津",
"唐山",
"邯郸",
"邢台",
"保定",
"承德",
"沧州",
"廊坊",
"衡水",
"太原",
"大同",
"阳泉",
"长治",
"晋城",
"朔州",
"晋中",
"运城",
"忻州",
"临汾",
"吕梁",
"包头",
"乌海",
"赤峰",
"通辽",
"沈阳",
"大连",
"鞍山",
"抚顺",
"本溪",
"丹东",
"锦州",
"营口",
"阜新",
"辽阳",
"盘锦",
"铁岭",
"朝阳",
"长春",
"吉林",
"四平",
"辽源",
"通化",
"白山",
"松原",
"白城",
"鸡西",
"鹤岗",
"大庆",
"伊春",
"黑河",
"绥化",
"上海",
"南京",
"无锡",
"徐州",
"常州",
"苏州",
"南通",
"淮安",
"盐城",
"扬州",
"镇江",
"泰州",
"宿迁",
"杭州",
"宁波",
"温州",
"嘉兴",
"湖州",
"绍兴",
"金华",
"衢州",
"舟山",
"台州",
"丽水",
"合肥",
"芜湖",
"蚌埠",
"淮南",
"淮北",
"铜陵",
"安庆",
"黄山",
"滁州",
"阜阳",
"宿州",
"六安",
"亳州",
"池州",
"宣城",
"福州",
"厦门",
"莆田",
"三明",
"泉州",
"漳州",
"南平",
"龙岩",
"宁德",
"南昌",
"萍乡",
"九江",
"新余",
"鹰潭",
"赣州",
"吉安",
"宜春",
"抚州",
"上饶",
"济南",
"青岛",
"淄博",
"枣庄",
"东营",
"烟台",
"潍坊",
"济宁",
"泰安",
"威海",
"日照",
"临沂",
"德州",
"聊城",
"滨州",
"菏泽",
"郑州",
"开封",
"洛阳",
"安阳",
"鹤壁",
"新乡",
"焦作",
"濮阳",
"许昌",
"漯河",
"南阳",
"商丘",
"信阳",
"周口",
"武汉",
"黄石",
"十堰",
"宜昌",
"襄阳",
"鄂州",
"荆门",
"孝感",
"荆州",
"黄冈",
"咸宁",
"随州",
"长沙",
"株洲",
"湘潭",
"衡阳",
"邵阳",
"岳阳",
"常德",
"益阳",
"郴州",
"永州",
"怀化",
"娄底",
"广州",
"韶关",
"深圳",
"珠海",
"汕头",
"佛山",
"江门",
"湛江",
"茂名",
"肇庆",
"惠州",
"梅州",
"汕尾",
"河源",
"阳江",
"清远",
"东莞",
"中山",
"潮州",
"揭阳",
"云浮",
"南宁",
"柳州",
"桂林",
"梧州",
"北海",
"钦州",
"贵港",
"玉林",
"百色",
"贺州",
"河池",
"来宾",
"崇左",
"海口",
"三亚",
"三沙",
"儋州",
"重庆",
"成都",
"自贡",
"泸州",
"德阳",
"绵阳",
"广元",
"遂宁",
"内江",
"乐山",
"南充",
"眉山",
"宜宾",
"广安",
"达州",
"雅安",
"巴中",
"资阳",
"贵阳",
"遵义",
"安顺",
"毕节",
"铜仁",
"昆明",
"曲靖",
"玉溪",
"保山",
"昭通",
"丽江",
"普洱",
"临沧",
"拉萨",
"昌都",
"林芝",
"山南",
"那曲",
"西安",
"铜川",
"宝鸡",
"咸阳",
"渭南",
"延安",
"汉中",
"榆林",
"安康",
"商洛",
"兰州",
"金昌",
"白银",
"天水",
"武威",
"张掖",
"平凉",
"酒泉",
"庆阳",
"定西",
"陇南",
"西宁",
"海东",
"银川",
"吴忠",
"固原",
"中卫",
"哈密"
],
"company_suffixes":[
"企业管理咨询有限责任公司",
"企业管理咨询责任有限公司",
"信息科技有限责任公司",
"信息科技责任有限公司",
"管理咨询责任有限公司",
"管理咨询有限责任公司",
"企业管理咨询有限公司",
"信息技术有限责任公司",
"信息技术责任有限公司",
"科技股份有限公司",
"科技有限责任公司",
"科技责任有限公司",
"信息科技有限公司",
"咨询有限责任公司",
"咨询责任有限公司",
"管理咨询有限公司",
"信息技术有限公司",
"技术有限责任公司",
"技术责任有限公司",
"管理有限责任公司",
"管理责任有限公司",
"责任有限公司",
"有限责任公司",
"股份有限公司",
"科技有限公司",
"信息有限公司",
"咨询有限公司",
"技术有限公司",
"管理有限公司",
"有限公司"
]
}
真实效果图如下:
如果需要圆形的可以在方法上设置锐化值,也可以让前端去锐化,都行。
分享到此结束,需要可以帮助到你,如果有什么不懂得可以留言,小编看到一定会回复你的疑问