代码可以直接运行,所有参数都提取成了常量,几乎都可以修改(除了256色阶)
package graph;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 随机产生类似Github的马赛克风格头像
* @author LLH
*/
public class GenerateMosaicHeadImg {
/** 背景颜色 */
private final static Color BACK_GROUND_COLOR = new Color(238, 238, 238);
/** 图片宽 */
private final static int IMG_WIDTH = 360;
/** 图片高 */
private final static int IMG_HEIGHT = 360;
/** 图片边缘内边距 */
private final static int PADDING = 30;
/** 填充比率,越接近1,有色色块出现几率越高 */
private final static double RADIO = 0.45;
/** 每边矩形数量(建议>=5) */
private final static int BLOCK_NUM = 9;
/** 颜色差值评价值(越大颜色越鲜艳) */
private final static int COLOR_DIFF_EVALUATION = 100;
/** 基色阶数极限 */
private final static int COLOR_LIMIT = 256;
/** 保存路径 */
private final static String DIR = "D://headImg/";
public static void main(String[] args) throws IOException {
//得到图片缓冲区
BufferedImage bi = new BufferedImage
(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_RGB);
//得到它的绘制环境(这张图片的笔)
Graphics2D g2 = (Graphics2D) bi.getGraphics();
//设置背景颜色
g2.setColor(BACK_GROUND_COLOR);
g2.fillRect(0, 0, IMG_WIDTH, IMG_HEIGHT);
// 随机颜色
Color mainColor = getRandomColor();
// 随机生成有效块坐标集合
List<Point> pointList = getRandomPointList(RADIO);
// 填充图形
fillGraph(g2, pointList, mainColor);
File file = new File(DIR);
if (!file.exists()) {
file.mkdirs();
}
// 输出
ImageIO.write(bi,"JPG",
new FileOutputStream(DIR+System.currentTimeMillis()+".jpg"));//保存图片 JPEG表示保存格式
}
/**
* 填充图形
* @param g2 画笔
* @param pointList 填充块坐标
* @param mainColor 填充颜色
*/
private static void fillGraph(Graphics2D g2, List<Point> pointList, Color mainColor) {
int rowBlockLength = (IMG_HEIGHT - 2 * PADDING) / BLOCK_NUM;
int colBlockLength = (IMG_WIDTH - 2 * PADDING) / BLOCK_NUM;
// 填充
g2.setColor(mainColor);
// 遍历points
for (Point point : pointList) {
g2.fillRect(PADDING + point.x * rowBlockLength,
PADDING + point.y * colBlockLength,
rowBlockLength, colBlockLength);
}
}
/**
* 获取随机颜色位置列表
* @param radio 填充色块几率
* @return List 列表
*/
private static List<Point> getRandomPointList(double radio) {
ArrayList<Point> points = new ArrayList<>();
for (int i = 0; i < BLOCK_NUM/2; i++) {
for (int j = 0; j < BLOCK_NUM; j++) {
if (Math.random() < radio) {
points.add(new Point(i, j));
}
}
}
addReversePoints(points);
if (BLOCK_NUM % 2 == 1) {
for (int i = 0; i < BLOCK_NUM; i++) {
if (Math.random() < radio) {
points.add(new Point(BLOCK_NUM/2, i));
}
}
}
return points;
}
/**
* 获取随机颜色
* @return Color对象
*/
private static Color getRandomColor() {
int r, g, b;
do {
r = new Random().nextInt(COLOR_LIMIT);
g = new Random().nextInt(COLOR_LIMIT);
b = new Random().nextInt(COLOR_LIMIT);
} while (evaluateColor(r, g, b));
return new Color(r, g, b);
}
/**
* 评价颜色品质,只需任意两种颜色差值大于某个规定值即可
* @return boolean
*/
private static boolean evaluateColor(int r, int g, int b) {
int rg = Math.abs(r - g);
int rb = Math.abs(r - b);
int gb = Math.abs(g - b);
int max = rg > rb ? (rg > gb ? rg : gb) : (rb > gb ? rb : gb);
return max < COLOR_DIFF_EVALUATION;
}
/**
* 添加对称坐标
* @param points point的列表
*/
private static void addReversePoints(List<Point> points) {
ArrayList<Point> pointListCopy = new ArrayList<>(points);
for (Point point : pointListCopy) {
points.add(new Point((BLOCK_NUM-1-point.x), point.y));
}
}
/**
* 封装了坐标的内部类
*/
private static class Point {
private int x;
private int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
}
package image
import (
"fmt"
"image"
"image/color"
"image/jpeg"
"math"
"math/rand"
"os"
"time"
)
const (
// 图片边距
imgSize = 360
// 图片边缘内边距
padding = 30
// 填充比率
ratio = 0.49
// 每边矩形数量
blockNum = 9
// 颜色差值评价值(越大颜色越鲜艳)
colorDiffEvaluation = 100
// 基色阶数(默认256)
colorLimit = 256
// 保存路径
dir = "D://headImg"
)
var (
// 背景颜色
backGroundColor = color.Gray{Y: 238}
)
// 坐标点
type point struct {
x, y uint
}
/**
* 主方法
* @author LLH
*/
func NewMosaicHeadImg() (err error) {
// 图片初始化
img := image.NewRGBA(image.Rect(0, 0, imgSize, imgSize))
fillBackGround(img)
// 随机颜色
randomColor := getRandomColor()
// 有色坐标块集合
pointList := generateRandomPointList()
// 填充色块
fillGraph(img, randomColor, pointList)
// 写IO
err = os.MkdirAll(dir, os.ModePerm)
if err != nil {
return
}
file, err := os.Create(fmt.Sprintf("%s/%d.jpg", dir, time.Now().UnixNano()))
if err != nil {
return
}
defer file.Close()
err = jpeg.Encode(file, img, nil)
fmt.Println("done!")
return
}
// 填充色块
func fillGraph(img *image.RGBA, c *color.RGBA, points *[]point) {
blockLen := uint(imgSize-2*padding) / blockNum
// 填充
for _, p := range *points {
fillRect(img, p.x*blockLen+padding, p.y*blockLen+padding, blockLen, blockLen, c)
}
}
// 获取随机坐标点切片
func generateRandomPointList() *[]point {
points := make([]point, 0)
// 获取半边随机点
for x := 0; x < blockNum/2; x++ {
for y := 0; y < blockNum; y++ {
pointsGrowUp(&points, x, y)
}
}
// 生成另一半的随机点
addReversePoints(&points)
if blockNum%2 == 1 {
for i := 0; i < blockNum; i++ {
pointsGrowUp(&points, blockNum/2, i)
}
}
return &points
}
// 添加随机坐标
func pointsGrowUp(points *[]point, x int, y int) {
seed := getRandSeed()
if seed.Float64() < ratio {
*points = append(*points, point{uint(x), uint(y)})
}
}
// 添加对称点
func addReversePoints(points *[]point) {
for _, p := range *points {
*points = append(*points, point{blockNum - 1 - p.x, p.y})
}
}
// 获取随机颜色
func getRandomColor() *color.RGBA {
var r, g, b int16
for {
r = randomColorBaseValue()
g = randomColorBaseValue()
b = randomColorBaseValue()
if evaluateColor(r, g, b) {
return &color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 100}
}
}
}
// 获取随机颜色基色值
func randomColorBaseValue() int16 {
seed := getRandSeed()
return int16(seed.Int31() & (colorLimit - 1))
}
// 获取随机数种子
func getRandSeed() *rand.Rand {
seed := rand.New(rand.NewSource(time.Now().UnixNano()))
time.Sleep(time.Nanosecond)
return seed
}
// 评价颜色鲜艳程度,足够鲜艳则返回 bool
func evaluateColor(r int16, g int16, b int16) bool {
rg := math.Abs(float64(r - g))
rb := math.Abs(float64(r - b))
gb := math.Abs(float64(g - b))
var max = math.Max(rg, rb)
max = math.Max(max, gb)
return max > colorDiffEvaluation
}
// 填充背景色
func fillBackGround(image *image.RGBA) {
fillRect(image, 0, 0, imgSize, imgSize, backGroundColor)
}
// 填充矩形的颜色
func fillRect(image *image.RGBA, x0, y0 uint, width, height uint, color color.Color) {
rgba := colorConverter(color)
for x := x0; x < x0+width; x++ {
for y := y0; y < y0+height; y++ {
image.SetRGBA(int(x), int(y), rgba)
}
}
}
// 得到类型为RGBA的颜色
func colorConverter(c color.Color) color.RGBA {
r, g, b, a := c.RGBA()
return color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: uint8(a)}
}