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

前言

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

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android 图片编码之必备技能

在进行 Android 开发时&#xff0c;不可避免地会接触到许多图片格式&#xff0c;例如 JPEG、PNG 等。就以 JPEG 格式为例&#xff0c;它是一种有损压缩模式&#xff0c;使用 YCbCr 的颜色空间来保存色彩信息。当需要在屏幕上显示图片时&#xff0c;会将 JPEG 数据解码成 RGB 进…

如何对项目进度进行跟踪?逐步完善项目计划

我接手了一个小项目&#xff0c;但是无论是我还是领导&#xff0c;都认为这是个简单的项目&#xff0c;最多一月时间就能搞定。但是&#xff0c;随着时间推移&#xff0c;三个月也没有将内容完善。于是我进行了反思总结&#xff0c;我认为存在如下问题&#xff1a; 1、资源协…

spring源码篇(八)事务的原理

文章目录 前言基本操作验证 Spring事务的传播机制特殊的机制说明NOT_SUPPORTEDNESTEDSUPPORTS 源码加载事务自动配置类要不要加注解&#xff1a;EnableTransactionManagement配置类说明 EnableTransactionManagement 做了什么AutoProxyRegistrar做了什么创建的代理类是jdk动态代…

【Nodejs】使用Nodejs搭建HTTP服务,并实现公网远程访问

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 转载自内网穿透工具的文章&#xff1a;使用Nodejs搭建HTTP服务&#xff0c;并实现公网远程访问「内网穿透」 前言 Node.js…

数据结构与算法·第2章【线性表】

线性结构具有以下基本特征&#xff1a; 有唯一的一个被称为首元素&#xff08;或头元素&#xff09;的元素&#xff0c;没有直接前驱&#xff1b;有唯一的一个被称为尾元素&#xff08;或尾节点&#xff09;的元素&#xff0c;没有直接后继。 数据元素之间存在一对一的线性关…

磐维数据库panweidb单节点服务器在centos7.9安装(研发环境)

一、系统环境优化 1.1 关闭SELINUX # 修改配置文件 cat /etc/selinux/config | grep -i SELINUX SELINUXdisabled# 关闭SELINUX setenforce 0 1.2 内核参数优化 vi /etc/sysctl.conf 添加# panweidb net.ipv4.tcp_max_tw_buckets 10000 net.ipv4.tcp_tw_reuse 1 net.ipv4.t…

ssm+springboot+java高校图书馆图书借阅座位预约管理系统系统

陕理工图书馆管理系统包括多个功能模块&#xff1a;图书类别管理模块、图书管理模块、读者管理模块、借阅管理模块、预约管理、推荐管理。管理员登入后&#xff0c;维护图书借阅的信息。本文介绍了使用Java技术开发陕理工图书馆管理系统的设计与实现过程&#xff0c;首先对实现…

【源码分析】【netty】FastThreadLocal 为什么快?

写在前面 接下来几篇文章&#xff0c;我们来聊一聊 netty 相关的。这里作者想先从 FastThreadLocal 开始说&#xff0c;而不是可能大家更熟悉的 reactor 啊&#xff0c;责任链设计啊&#xff0c;ByteBuf 啊&#xff0c;池化啊等等。不过虽然说 FastThreadLocal 熟知程度不如其…

2023年湖北建筑架子工报名流程?报名需要什么资料?考试一次过?

2023年湖北建筑架子工报名流程&#xff1f;报名需要什么资料&#xff1f;考试一次过&#xff1f; 建筑架子工证是建筑行业必备的证书之一&#xff0c;它是证明持有人可以在建筑工地上从事搭建脚手架、模板等施工工作的重要证明。启程别告诉你架子工的报名流程和资料。 百度搜一…

示范性微电子院校“抢人”,芯片赛道黄不了!

经常看到有同学问&#xff0c;“国内高校微电子专业最好的是哪所高校?”“想搞数字ic设计去哪所大学好呢&#xff1f;” 其实国内28所示范性微电子学院都是非常不错的选择。 2015年&#xff0c;九所示范性微电子院校名单公布&#xff0c;包括了清华大学、北京大学、复旦大学…

【7 Vue3 – Composition API】

1 认识Composition API Options API的弊端 setup函数 2 setup函数的参数 3 setup简单使用 1 注意不再有响应式数据 要做到响应式数据需要在数据定义时使用ref包装数据,并且在使用时,使用value解包 2 注意template要使用的数据或者函数,必须要return 返回才能被使用 <templa…

软考A计划-软件设计师笔记

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

MT4期货软件怎么使用?有哪些MT4期货软件使用知识?

现在MT4软件在投资市场上应用广泛&#xff0c;当然也包括期货交易市场&#xff0c;但有不少投资者不知道为什么一定要选择MT4期货软件&#xff0c;其实选择MT4期货软件的理由有很多&#xff0c;MT4作为一款交易软件&#xff0c;不仅能够为投资者提供准确的市场信息&#xff0c;…

02SpringCloud Nacos注册中心和配置中心与Sentinel服务熔断和流控

Nacos注册中心和配置中心 Nacos 是 Alibaba 开发的用于微服务管理的平台&#xff0c;核心功能&#xff1a;服务注册与发现和集中配置管理。 Nacos 作为服务注册发现组件&#xff0c;可以替换Spring Cloud 应用中传统的服务注册于发现组件&#xff0c;如&#xff1a;Eureka、C…

Ai作图可控性演进——从SD到MJ

背景 Ai作图从Diffusion模型开始&#xff0c;作图进入稳步发展快车道。然后用过diffusion系列作图的同学对产图稳定性&#xff0c;以及可控性都会颇有微词。diffusion系列作图方法在宏观层面上确实能够比较好的做出看上去还不错的图。然后当你细抠细节时候&#xff0c;发现这东…

如何在Windows 11更新后解决C盘已满的问题?

Windows 11比Windows 10需要占用C盘更多的空间&#xff0c;在升级到Windows 11后&#xff0c;如果升级后出现问题&#xff0c;安装程序可以帮你退回到Windows 10。无论怎样&#xff0c;在升级到Windows 11后&#xff0c;系统会自动制作以前的数据的副本&#xff0c;这会占用大量…

win7下java环境搭建以及jdk环境变量配置

很多人在搭建页游、手游时候经常遇到JAVA闪退&#xff0c;基本都是环境变量或者路径错误导致的。本章节主要讲解在win7系统环境下&#xff0c;java环境变量配置方法&#xff0c;java环境配置正确&#xff0c;才可以对apk程序进行反编译运行页游手游。其他操作系统环境变量大同小…

Mesh形变算法

前言&#xff1a; 作者正好因为动画、模拟仿真等等的重大需求需要预先研发离散形的模型Mesh的形变算法&#xff0c;并且要验证、研究适用的范围、特别是性能等等&#xff0c;摸着石头过河别喷&#xff0c;毕竟我主要是渲染、动画、引擎的对于计算几何、三维重建不是很熟悉&…

一体化医学影像平台PACS源码,影像存档与传输系统源码

PACS影像存档与传输系统源码 PACS即影像存档与传输系统&#xff0c;是医学影像、数字化图像技术、计算机技术和网络通讯技术相结合的产物&#xff0c;是处理各种医学影像信息的采集、存储、报告、输出、管理、查询的计算机应用程序。 是基于DICOM标准的医学影像管理系统&…

大龄、零基础,想转行做网络安全。怎样比较可行?这届粉丝可真难带

昨晚上真的给我气孕了。 对于一直以来对网络安全兴趣很大&#xff0c;想以此作为以后的职业方向的人群。 不用担心&#xff0c;你可以选择兼顾工作和学习&#xff0c;以步步为营的方式尝试转行到网络安全领域。 那么&#xff0c;网络安全到底要学些什么呢&#xff1f; &…