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

news2024/11/24 8:56:52

前言

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

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/472556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第N2周:中文文本分类-Pytorch实现

目录 一、前言二、准备工作三、数据预处理1.加载数据2.构建词典3.生成数据批次和迭代器 三、模型构建1. 搭建模型2. 初始化模型3. 定义训练与评估函数 四、训练模型1. 拆分数据集并运行模型 一、前言 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客 …

运算符重载----赋值运算符重载

运算符重载 本质是函数调用&#xff0c;内置类型编译器直接比&#xff0c;自定义就去找对应类内重载的函数 如果定义在类外&#xff0c;需要访问私有的成员函数&#xff0c;只能将成员函数权限变为Public或者友元&#xff08;非必须不用&#xff09; &#xff0c;所以一般重载…

Linux程序设计之字节序转换

1.在网络通信中&#xff0c;数据的存储方式十分重要&#xff0c;因为它影响到数据的准确性。如今&#xff0c;电脑和网络上数据的存储方式有两种&#xff1a;大端模式和小端模式。大端模式&#xff1a;数据的高位存储在内存的低位&#xff0c;数据的低位存储在内存的高位。小端…

【keil5开发ARM工程时使用STLink调试的技巧分享】

ARM工程开发小技巧系列文章 St link V2驱动安装方法 文章目录 ARM工程开发小技巧系列文章前言一、准备工作1. 硬件连接2. 安装stlink的驱动3. Keil 5配置 二、调试示例1.进入调试状态2. 调试演示2.1 复位&#xff0c;使程序复位到初始位置2.2 单步调试2.3 逐步调试2.4 跳出调…

Quartus中的逻辑锁定与增量编译

逻辑锁定功能可以将FPGA中的代码模块在固定区域实现&#xff0c;优化时序性能&#xff0c;提升设计可靠性。增量编译功能&#xff0c;可以使设计更快速时序收敛&#xff0c;加快编译速度。 LogicLock 使用Chip Planner创建逻辑锁定区域 打开Chip Planner&#xff0c;点击Vie…

Kubernetes Controller原理讲解

Controller原理 在 K8s 中&#xff0c;用户通过声明式 API 定义资源的“预期状态”&#xff0c;Controller 则负责监视资源的实际状态&#xff0c;当资源的实际状态和“预期状态”不一致时&#xff0c;Controller 则对系统进行必要的更改&#xff0c;以确保两者一致&#xff0…

人群计数数据集汇总和详细介绍,全网最全,crowd counting datasets

Crowd Counting数据集汇总 视频监控video surveillance https://github.com/gjy3035/Awesome-Crowd-Counting/blob/master/src/Datasets.md进展 | 密集人群分布检测与计数 :https://www.sohu.com/a/338406719_823210 Free-view 2022_Pedestrian Attribute Recognition htt…

vue+element Ui 树型组件tree懒加载+搜索框远程请求数据为平铺类型

本人之前一直是耕耘后台研发&#xff0c;最近接了个小需求需要接触到vue&#xff0c;记录一下我遇到的一些前端解决时间长的问题 需求&#xff1a; 1&#xff1a;每次动态请求接口获取下一节点数据 2&#xff1a;接口返回的数据是list&#xff0c;不带子节点&#xff0c;用pid来…

Scala中使用Typesafe Config 库

Typesafe Config 库 在 Scala 中加载配置文件有很多种方法&#xff0c;其中一种常用的方法是使用 Typesafe Config 库。该库提供了一种简单易用的方式来读取和解析配置文件。 以下是在启动 main 方法后加载配置文件的示例代码&#xff1a; 引入 Typesafe Config 库 import c…

【MySQL】函数

一、概述 MySQL中提供了大量函数来简化用户对数据库的操作&#xff0c;比如字符串的处理、日期的运算、数值的运算等等。使用函数可以大大提高SELECT语句操作数据库的能力&#xff0c;同时也给数据的转换和处理提供了方便。 &#xff08;在sql中使用函数&#xff09;函数只是对…

shadowsocks服务端和客户端搭建

shadowsocks服务端和客户端搭建 一、服务端搭建 买个境外云服务器&#xff0c;搭建shadowsocks服务端。 需要python3环境。 1.下载shadowsocks服务端python包&#xff0c;并启动。下载地址 # 1.下载 [rootiZrj982e4r5hkd053zsnmqZ ~]# wget https://pypi.python.org/packa…

2023隐私计算与人工智能峰会成功举办!数据宝演讲实录(上篇)分享

2023年4月8日&#xff0c;2023隐私计算与人工智能峰会在深圳举办&#xff0c;大会由华东江苏大数据交易中心和热点资讯联合主办&#xff0c;会上&#xff0c;数据宝董事詹臻女士做开幕式致辞。 数据宝与开放群岛&#xff08;Open Islands&#xff09;进行战略签约&#xff0c;…

LoRA: 大语言模型个性化的最佳实践

出品人&#xff1a; Towhee 技术团队 大型语言模型&#xff08;LLM&#xff09;在今年获得了极大的关注。在以往&#xff0c;预训练微调&#xff08;finetuning&#xff09;成为了让模型适配于特定数据的最佳范式。然而随着大型模型的出现&#xff0c;这种完全微调&#xff08;…

【运动规划算法项目实战】如何实现机器人多目标点导航

文章目录 前言一、 什么是actionlib?二、实现流程三、总结前言 在ROS机器人应用中,实现机器人多目标点导航是非常常见的需求。本文将介绍如何使用ROS和actionlib来实现机器人的多目标点导航,目标点信息将被记录在YAML文件中。 我们可以通过使用MoveBaseAction来实现机器人…

高并发场景下JVM调优实践

一、背景 2021年2月&#xff0c;收到反馈&#xff0c;视频APP某核心接口高峰期响应慢&#xff0c;影响用户体验。 通过监控发现&#xff0c;接口响应慢主要是P99耗时高引起的&#xff0c;怀疑与该服务的GC有关&#xff0c;该服务典型的一个实例GC表现如下图&#xff1a; 可以…

【WinForm】定时器的使用方法除了定时还有延迟执行可用

在使用VS开发工具创建的WinForm项目中&#xff0c;有一个定时器组件&#xff0c;拖出来放上&#xff0c;它只是一个定时处理的作用&#xff0c;不会显示在窗体中。 开发中如果需要定时处理&#xff0c;就使用Timer组件即可&#xff0c; 在它的属性事件一栏里&#xff0c;有一…

offer选择:创业公司 VS 大厂外包

面试拿到两个offer&#xff0c;一个是规模只有几十人的初创小公司&#xff0c;另一个是大厂外包岗位。都是功能测试&#xff0c;两者薪水待遇也差不多&#xff0c;该如何选择?更有利于之后的职业发展...... 这是一个比较典型的问题&#xff0c;对于要转行的同学或者是刚入行没…

【Call for papers】2023年CCF人工智能会议信息汇总(持续更新)

本博文是根据2022年CCF会议推荐的人工智能领域相关会议目录撰写。 注&#xff1a; 由于一些会议的投稿时间还没公开&#xff0c;因此根据往年投稿时间在表格中使用 ~ 符号表示大概的投稿时间&#xff08;一旦会议日期更新&#xff0c;我们也将同步更新博文。若更新不及时请小伙…

C++常用23种设计模式总结(一)------单例模式

什么是单例模式 单例模式是一种设计模式&#xff0c;它保证一个类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。这个模式通常用于控制资源的访问&#xff0c;例如数据库连接、线程池等。单例模式通过限制实例化操作并提供访问方法&#xff0c;确保在整个应用程序…

【Unity3D小功能】Unity3D中实现模型的旋转、缩放效果(控制摄像机)

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 其实之前已经写了关于如何控制模型的旋转、移动、缩放效果&…