【原创】生成文件MD5图像,类似于GitHub的像素风格头像

news/2024/9/23 8:15:53/

前言

我想通过文件的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还是1char[] 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和我同一个版本的话,那么生成的图片应该是一模一样的,当然这个也可以用作头像

 

 


http://www.ppmy.cn/news/56286.html

相关文章

GeoTools实战指南: 轻松实现GeoTIFF与Shapefile的可视化和叠加

GeoTools实战指南: 轻松实现GeoTIFF与Shapefile的可视化和叠加 介绍 本教程将指导您如何使用GeoTools库渲染栅格数据(GeoTIFF文件)和矢量数据(Shapefile文件),并将它们叠加在地图窗口中显示。下面是基于提供的代码示例的教程。 准备环境 首先,您需要将GeoTools库添加…

matlab 实现常用的混沌映射(Tent, Sine, Sinusoidal, Piecewise, Logistic, Cubic, Chebyshev)

大部分混沌映射的系数是有限制的, 针对每个模型最优的混沌系数是不一样的, 因此混沌系数要根据自己的模型来定. 下面的系数都是根据我自己的模型而设定的. 混沌映射 1 Tent 映射2 Sine 映射3 Sinusoidal 映射4 Piecewise 映射5 Logistic 映射6 Cubic 映射7 Chebyshev 映射 1 Te…

ARL灯塔(无需VPS版)

标题随便写&#xff0c;能看到都是有缘人 搭建灯塔那么繁琐的步骤&#xff0c;远不如爆破一个灯塔是吧(狗头) 而且还可能买不起VPS的情况(例如我) 那不如写一个脚本去爆破灯塔的弱口令 整治网络安全 从你我做起 fofa语法&#xff1a; icon_hash"1708240621"…

大数据技术ELK实时检索

一 elasticsearch简介 ElasticSearch是一个高性能&#xff0c;基于Lucene的全文检索服务&#xff0c;是一个分布式的Restful风格的搜索和数据分析引擎&#xff0c;也可以作为NoSQL数据库使用。 对Lucene进行了扩展 原型环境和生产环境可无缝切换 能够水平扩展 支持结构化和非结…

python的多任务处理

在现代计算机系统中&#xff0c;多任务处理是一项重要的技术&#xff0c;可以大幅提高程序的运行效率。Python语言提供了多种多任务处理的方式&#xff0c;本文将介绍其中几种常见的方式&#xff0c;包括多进程、多线程和协程。 多进程 进程是计算机中运行程序的实例&#xf…

Chatgpt创业机AIGC正在进行的行业

Marketing&#xff1a;人工智能在营销领域的应用主要涉及市场调研、产品推广、内容生产等方面&#xff0c;例如通过机器学习技术分析用户行为和偏好&#xff0c;帮助企业更好地了解目标受众并进行精准营销。 General Writing&#xff1a;自然语言生成技术可以帮助用户自动生成…

TCP,TCP 连接建立,TCP 连接断开,Socket 编程

目录 TCP基本认识 TCP 头格式有哪些&#xff1f; 为什么需要 TCP 协议&#xff1f; TCP 工作在哪一层&#xff1f; 什么是 TCP &#xff1f; 什么是 TCP 连接&#xff1f; #如何唯一确定一个 TCP 连接呢&#xff1f; UDP 和 TCP 有什么区别呢&#xff1f;分别的应用场景是…

数据降维 | MATLAB实现基于LFDA基于局部费歇尔判别的分类数据降维可视化

数据降维 | MATLAB实现基于LFDA基于局部费歇尔判别的分类数据降维可视化 目录 数据降维 | MATLAB实现基于LFDA基于局部费歇尔判别的分类数据降维可视化基本介绍模型描述程序设计学习小结基本介绍 MATLAB实现基于LFDA基于局部费歇尔判别的分类数据降维可视化 模型描述 局部费歇尔…