[Original] Genere una imagen de archivo MD5, similar al avatar de estilo píxel de GitHub

prefacio

Quiero generar una imagen sobre este md5 a través del md5 del archivo, que es similar al avatar de píxeles aleatorios de GitHub. El propósito es hacer que este md5 sea más intuitivo, y también se puede usar para generar varios avatares de usuario, al igual que GitHub. .

Busqué en Internet, pero no hay un método listo para usar, solo hay un artículo similar que se puede usar como referencia, pero ese artículo es una cadena aleatoria, y el mío es un archivo, que es una cadena fija, y no cambiar el numero de columnas Utilizo esto como base y simplemente lo cambio.

Contenido de referencia: Cree una forma aleatoria y un avatar estilo píxel de color aleatorio similar a Github_github pixel avatar_LLH_Durian's Blog-CSDN Blog

Principio del algoritmo

Dado que md5 es una cadena compuesta por 32 caracteres, entonces puedes volver a armar un gran alboroto al respecto. Mi método de cálculo es:

El valor promedio de 0~9 dígitos se toma como r (rojo), el valor promedio de 10~19 dígitos se considera g (verde), y el valor promedio de 20~31 dígitos se considera b (azul), entonces el color del avatar ha sido determinado.

El siguiente paso es determinar el número de píxeles en la imagen. Después de una cuidadosa consideración, finalmente determiné que era 8*16, es decir, hay 8 columnas de píxeles y cada columna tiene 16 filas. Dado que el avatar es simétrico, es 16*16 después de reflejar una imagen.

Esa es la situación como se muestra en la figura:

Dado que las 4 cadenas hexadecimales tienen exactamente una longitud binaria de 16 bits, solo pueden llenar una columna. Las llenaré con 1 y no con 0, y luego se puede dibujar la imagen a partir de ella.

Código

El código es un poco largo, pero muchos son comentarios, necesita introducir Hutool para ejecutarlo

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;
    }
}

alcanzar resultados

Permítanme tomar el paquete de guerra de Jenkins como ejemplo, el efecto generado es el siguiente:

Si su Jenkins es la misma versión que la mía, entonces la imagen generada debería ser exactamente igual, por supuesto, esto también se puede usar como avatar.

 

 

Supongo que te gusta

Origin blog.csdn.net/DCTANT/article/details/130431798
Recomendado
Clasificación