我想通过文件的md5生成关于这个md5的图像,类似于GitHub的随机像素头像,用处是让这个md5更加直观,也能用于生成各种用户头像,跟GitHub一样。
网上搜了一下,没有现成的方法,只能有一篇类似的文章可以借鉴一下,但是那篇是随机的字符串,而我的是文件,是固定的字符串,且不要改变列的数量,那我以此为基础,改一下就行了。
参考的内容:实现类似于Github的随机形状、随机颜色 像素风格头像_github像素头像_LLH_Durian的博客-CSDN博客
由于md5是一个32位字符组成的字符串,那就可以再次上面大做文章了,我的计算方式为:
0~9位取平均值作为r(red),10~19位取平均值作为g(green),20~31位取平均值作为b(blue),那么头像的颜色就已经决定下来了。
接下来就是确定图像的像素数量,经过我的深思熟虑后,最终确定下来为8*16,即一共有8列像素,每列16行,由于头像是对称的,因此镜像一下,就是16*16的一张图片。
也就是如图所示的情况:
由于4个十六进制字符串正好是二进制的16位长度,正好可以铺满一列,我这边将1填充,0不填充,然后图片就能由此绘制出来了。
代码有点长,不过很多都是注释,需要引入Hutool即可运行
- package com.itdct.md5pic;
-
- import org.apache.commons.lang3.StringUtils;
-
- import java.awt.Color;
- import java.awt.Graphics2D;
- import java.awt.image.BufferedImage;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.nio.charset.Charset;
-
- import javax.imageio.ImageIO;
-
- import cn.hutool.core.io.FileUtil;
- import cn.hutool.core.util.HexUtil;
- import cn.hutool.crypto.digest.MD5;
-
- /**
- * @author DCTANT
- * @version 1.0
- * @date 2023/4/28 15:55:23
- * @description 用于生成文件MD5图片的方法
- */
- public class GenerateMd5Pic {
- private MD5 md5 = new MD5();
- /**
- * 每个格子占据的像素大小
- */
- private int blockSize = 250;
- /**
- * 内边距,默认为两倍的格子宽度
- */
- private int padding = blockSize * 2;
- /**
- * 背景颜色,默认为白色
- */
- private Color backgroundColor = new Color(255, 255, 255);
- /**
- * 输出路径
- */
- private String outputPath;
- /**
- * 输入文件路径
- */
- private String filePath;
- /**
- * 是否输出md5文件
- */
- private boolean writeMd5File;
-
- /**
- * 通过32位长度的字符串生成图片
- *
- * @param hexString
- */
- public void string32Img(String hexString) {
- if (hexString.length() != 32) {
- throw new RuntimeException("输入字符串参数长度不是32");
- }
-
- // INFO: DCTANT: 2023/4/28 取RGB的总值
- String redTotal = hexString.substring(0, 10);
- String greenTotal = hexString.substring(10, 20);
- String blueTotal = hexString.substring(20, 32);
-
- // INFO: DCTANT: 2023/4/28 获取到平均后的rgb的值
- int r = getAverage256Value(redTotal);
- int g = getAverage256Value(greenTotal);
- int b = getAverage256Value(blueTotal);
- // INFO: DCTANT: 2023/4/28 定义每个格子的颜色
- Color blockColor = new Color(r, g, b);
-
- // INFO: DCTANT: 2023/4/28 计算图片的总像素宽度
- int picSize = 2 * padding + blockSize * 16;
-
- BufferedImage bufferedImage = new BufferedImage(picSize, picSize, BufferedImage.TYPE_INT_RGB);
-
- // INFO: DCTANT: 2023/4/28 获取图片画笔
- Graphics2D graphics2D = (Graphics2D) bufferedImage.getGraphics();
- // INFO: DCTANT: 2023/4/28 设置背景颜色
- graphics2D.setColor(backgroundColor);
- // INFO: DCTANT: 2023/4/28 画出整个背景
- graphics2D.fillRect(0, 0, picSize, picSize);
-
- boolean[][] blockArray = calculateBlockArray(hexString);
-
- graphics2D.setColor(blockColor);
- // INFO: DCTANT: 2023/4/28 绘制每个格子
- for (int column = 0; column < blockArray.length; column++) {
- boolean[] rows = blockArray[column];
- for (int row = 0; row < rows.length; row++) {
- boolean isBlock = rows[row];
- if (!isBlock) {
- continue;
- }
- // INFO: DCTANT: 2023/4/28 数值为1的,画出方格
- int x = padding + column * blockSize;
- int y = padding + row * blockSize;
- graphics2D.fillRect(x, y, blockSize, blockSize);
- }
- }
-
- if (StringUtils.isBlank(outputPath)) {
- if (StringUtils.isBlank(filePath)) {
- outputPath = "./" + hexString + ".jpg";
- } else {
- outputPath = filePath + ".md5.jpg";
- }
- }
-
- try {
- File file = new File(outputPath);
- System.out.println("输出路径为:" + file.getAbsolutePath());
- ImageIO.write(bufferedImage, "JPG", new FileOutputStream(outputPath));//保存图片 JPEG表示保存格式
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 通过十六进制字符串,计算出16*16的像素数组
- *
- * @param hexString
- * @return
- */
- private boolean[][] calculateBlockArray(String hexString) {
- boolean[][] blockArray = new boolean[16][16];
- for (int column = 0; column < 8; column++) {
- // INFO: DCTANT: 2023/4/28 将32位的md5,每4位切一个下来
- String fourHexString = hexString.substring(column * 4, (column + 1) * 4);
- // INFO: DCTANT: 2023/4/28 转为十进制
- int decimal = HexUtil.hexToInt(fourHexString);
- // INFO: DCTANT: 2023/4/28 十进制转二进制
- StringBuilder binaryBuilder = new StringBuilder(Integer.toBinaryString(decimal));
- // INFO: DCTANT: 2023/4/28 补零
- if (binaryBuilder.length() < 16) {
- int addZeroCount = 16 - binaryBuilder.length();
- for (int i = 0; i < addZeroCount; i++) {
- binaryBuilder.insert(0, "0");
- }
- }
-
- // INFO: DCTANT: 2023/4/28 转为字符数组,用于判断是0还是1
- char[] chars = binaryBuilder.toString().toCharArray();
- for (int row = 0; row < chars.length; row++) {
- char theOneOrZero = chars[row];
- if (theOneOrZero == '1') {
- blockArray[column][row] = true;
- // INFO: DCTANT: 2023/4/28 对称点赋值
- blockArray[15 - column][row] = true;
- } else {
- blockArray[column][row] = false;
- // INFO: DCTANT: 2023/4/28 对称点赋值
- blockArray[15 - column][row] = false;
- }
- }
- }
- return blockArray;
- }
-
- /**
- * 通过文件生成其MD5图像
- *
- * @param filePath
- */
- public void fileImg(String filePath) {
- File file = new File(filePath);
- if (!file.exists()) {
- throw new RuntimeException("文件不存在");
- }
-
- String md5String = md5.digestHex(filePath);
- System.out.println("file md5 is " + md5String);
- if (writeMd5File) {
- FileUtil.writeString(md5String, filePath + ".md5", Charset.defaultCharset());
- }
- this.filePath = filePath;
- string32Img(md5String);
- }
-
- /**
- * 计算整个十六进制字符串的其中两位的平均值,并四舍五入
- *
- * @param hex 该十六进制字符串每两位的平均值
- * @return
- */
- public int getAverage256Value(String hex) {
- int loopCount = hex.length() / 2;
- if (hex.length() % 2 == 1) {
- throw new RuntimeException("hex长度必须为偶数");
- }
- double total = 0.0;
- for (int i = 0; i < loopCount; i++) {
- String twoHex = hex.substring(i * 2, (i + 1) * 2);
- int value = HexUtil.hexToInt(twoHex);
- total += value;
- }
- double value = total / loopCount;
- int result = new BigDecimal(value).setScale(0, RoundingMode.HALF_UP).intValue();
- return result;
-
- }
-
- public static void main(String[] args) {
- GenerateMd5Pic generateMd5Pic = new GenerateMd5Pic().setWriteMd5File(true);
- generateMd5Pic.fileImg("C:\\Tmp\test\\jenkins.war");
- }
-
- public String getFilePath() {
- return filePath;
- }
-
- public GenerateMd5Pic setFilePath(String filePath) {
- this.filePath = filePath;
- return this;
- }
-
- public int getBlockSize() {
- return blockSize;
- }
-
- public GenerateMd5Pic setBlockSize(int blockSize) {
- this.blockSize = blockSize;
- return this;
- }
-
- public int getPadding() {
- return padding;
- }
-
- public GenerateMd5Pic setPadding(int padding) {
- this.padding = padding;
- return this;
- }
-
- public String getOutputPath() {
- return outputPath;
- }
-
- public GenerateMd5Pic setOutputPath(String outputPath) {
- this.outputPath = outputPath;
- return this;
- }
-
- public GenerateMd5Pic setBackgroundColor(Color backgroundColor) {
- this.backgroundColor = backgroundColor;
- return this;
- }
-
- public boolean isWriteMd5File() {
- return writeMd5File;
- }
-
- public GenerateMd5Pic setWriteMd5File(boolean writeMd5File) {
- this.writeMd5File = writeMd5File;
- return this;
- }
- }
我就拿Jenkins的war包来举例吧,生成的效果如下:
如果你的Jenkins和我同一个版本的话,那么生成的图片应该是一模一样的,当然这个也可以用作头像