先上原图:
转换后的黑白字符图:
带颜色的顺序love图(图中的字符顺序是LOVE的顺序):
带颜色的LOVE无序布满字符图:
带颜色的LOVE有序布满字符图:
代码实现:
public static void main(String[] args) throws Exception {
// 使用字符来绘制图像的原理:(个人理解,可能不是很正确)
// 就是把一张图片的每个像素点的rgb表示一个灰度值,使用这个灰度值来计算对应的字符位置
// 顺序打印x轴y轴即可
// 绘制的字符串内容
String drawString = "love";
// 用来控制灰度值是否使用空格字符来表示,当这个值大于字符串长度*255的时候,只会使用字符来显示图像中的黑色
int density = 0;
// 绘制的图片地址
String imgPath = "C:\\tmp\\meme\\10_趣\\1.png";
String targetPath = "C:\\tmp\\meme\\10_趣\\10.png";
// pattern参数是用来控制是否顺序打印字符串内容,顺序打印字符一定要控制打印空白字符来填充,否则相同的字符排列就看不出图画的效果
// true的时候取的是字符串中计算出来的对应的字符,这样即使没有填充空格,也能根据字符的不同来显示图片的轮廓,false的时候则是按照
// 字符串中字符的顺序循环取,这样如果不填充空格,就看不出图片了(这种针对的是只有黑白两种颜色的情况,使用颜色来绘制的话一样能看出图片)
// 代码中有输出到控制台,具体可以看对应的控制台输出
characterPainting(drawString, density, imgPath, targetPath, false);
}
private static void characterPainting(String drawString, int density, String imgPath, String targetPath, boolean pattern) throws IOException {
int baseLength = drawString.length();
// 读取图片
BufferedImage image = ImageIO.read(new File(imgPath));
int width = image.getWidth();
int height = image.getHeight();
// 这个用来控制打印字符串中字符的索引位置
int charIndex = 0;
// 用来生成图片文件 11差不多是这个字体这个大小下所占用的像素大小
BufferedImage bufferedImage = new BufferedImage(width * 11, height * 11, BufferedImage.TYPE_INT_RGB);
Graphics graphics = bufferedImage.getGraphics();
// 填充背景
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width * 11, height * 11);
// 设置字体颜色 字体大小 字体
graphics.setColor(Color.black);
graphics.setFont(new Font("Consolas", Font.PLAIN, 16));
for (int y = 0; y < height; y++) {
// 拼接字符串(可以直接拼一行,画一行,也可以一个字符一个字符的画,以取到的rgb颜色来给字符增加颜色)
StringBuilder line = new StringBuilder();
for (int x = 0; x < width; x++) {
// 获取图片对应坐标的rgb
int rgb = image.getRGB(x, y);
// 一个int是4个字节
// 00000000 00000000(r) 00000000(g) 00000000(b) 获取对应的rgb只要移动对应的位数,并将高三位的置于0即可
int r = rgb >> 16 & 0xff;
int g = rgb >> 8 & 0xff;
int b = rgb & 0xff;
// 灰度值的计算方法,网上的,自己也可以顺便表示,但是用这个效果比较好
int gray = Math.round(0.299f * r + 0.587f * g + 0.114f * b);
// 计算一个比例,确定显示的字符的索引位置
int index = gray * (baseLength + density) / 255;
if (pattern) {
// true的时候,使用上面计算的字符串的索引位置
charIndex = index;
}
// 设置为当前取到的rgb
graphics.setColor(new Color(r, g, b));
// 计算绘制的坐标,y轴要+1,绘制字符时,y轴从0算的话,字符时绘制到画面以外的
int drawX = x * 11;
int drawY = (y + 1) * 11;
// 超出字符串长度了,直接打印空格
if (index >= baseLength) {
System.out.print(" ");
line.append(" ");
graphics.drawString(" ", drawX, drawY);
} else {
// 打印对应的字符
char c = drawString.charAt(charIndex);
System.out.print(c);
charIndex = (charIndex + 1) % baseLength;
line.append(c);
graphics.drawString(c + "", drawX, drawY);
}
}
System.out.println();
// 直接一行一行的绘制,这种不能添加原图对应的颜色
// graphics.drawString(line.toString(), 0, (y + 1) * 11);
}
ImageIO.write(bufferedImage, "png", new File(targetPath));
}