上面是寻找自定义图片 banner 文件源码,如果把图片转换成 ASCII 图案继续跟进,追踪方法1中的PrintedBanner(banner, sourceClass)方法。最终查找输出图案的主要方法。
// 位置:org.springframework.boot.ImageBanner#printBanner private void printBanner(BufferedImage image, int margin, boolean invert, PrintStream out) { AnsiElement background = invert ? AnsiBackground.BLACK : AnsiBackground.DEFAULT; out.print(AnsiOutput.encode(AnsiColor.DEFAULT)); out.print(AnsiOutput.encode(background)); out.println(); out.println(); AnsiColor lastColor = AnsiColor.DEFAULT; // 图片高度遍历 for (int y = 0; y < image.getHeight(); y++) { for (int i = 0; i < margin; i++) { out.print(" "); } // 图片宽度遍历 for (int x = 0; x < image.getWidth(); x++) { // 获取每一个像素点 Color color = new Color(image.getRGB(x, y), false); AnsiColor ansiColor = AnsiColors.getClosest(color); if (ansiColor != lastColor) { out.print(AnsiOutput.encode(ansiColor)); lastColor = ansiColor; } // 像素点转换成字符输出,调用方法记为2 out.print(getAsciiPixel(color, invert)); } out.println(); } out.print(AnsiOutput.encode(AnsiColor.DEFAULT)); out.print(AnsiOutput.encode(AnsiBackground.DEFAULT)); out.println(); } // 方法2,像素点转换成字符 private char getAsciiPixel(Color color, boolean dark) { // 根据 color 算出一个亮度值 double luminance = getLuminance(color, dark); for (int i = 0; i < PIXEL.length; i++) { // 寻找亮度值匹配的字符 if (luminance >= (LUMINANCE_START - (i * LUMINANCE_INCREMENT))) { // PIXEL = { ' ', '.', '*', ':', 'o', '&', '8', '#', '@' }; return PIXEL[i]; } } return PIXEL[PIXEL.length - 1]; }通过查看源码,发现 Springboot 的图片 banner 的转换和我们预想的大致一致,这么有趣的功能我们能不能自己写一个呢?
3.自己实现图片转 ASCII字符根据上面的分析,总结一下思路,我们也可以手动写一个图片转 ASCII 字符图案。
思路如下:
图片大小缩放,调整到合适大小。
遍历图片像素。
获取图片像素点亮度(RGB颜色通过公式可以得到亮度数值)。
匹配字符。
输出图案。
上面的5个步骤直接使用 Java 代码就可以完整实现,下面是编写的源码。
import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.imageio.ImageIO; /** * <p> * 根据图片生成字符图案 * 1.图片大小缩放 * 2.遍历图片像素点 * 3.获取图片像素点亮度 * 4.匹配字符 * 5.输出图案 * * @author niujinpeng * @website * @date 2019-02-25 23:03:01 */ public class GeneratorTextImage { private static final char[] PIXEL = {'@', '#', '8', '&', 'o', ':', '*', '.', ' '}; public static void main(String[] args) throws Exception { // 图片缩放 BufferedImage bufferedImage = makeSmallImage("src/main/resources/banner.jpg"); // 输出 printImage(bufferedImage); } public static void printImage(BufferedImage image) throws IOException { int width = image.getWidth(); int height = image.getHeight(); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int rgb = image.getRGB(j, i); Color color = new Color(rgb); int red = color.getRed(); int green = color.getGreen(); int blue = color.getBlue(); // 一个用于计算RGB像素点亮度的公式 Double luminace = 0.2126 * red + 0.7152 * green + 0.0722 * blue; double index = luminace / (Math.ceil(255 / PIXEL.length) + 0.5); System.out.print(PIXEL[(int)(Math.floor(index))]); } System.out.println(); } } public static BufferedImage makeSmallImage(String srcImageName) throws Exception { File srcImageFile = new File(srcImageName); if (srcImageFile == null) { System.out.println("文件不存在"); return null; } FileOutputStream fileOutputStream = null; BufferedImage tagImage = null; Image srcImage = null; try { srcImage = ImageIO.read(srcImageFile); int srcWidth = srcImage.getWidth(null);// 原图片宽度 int srcHeight = srcImage.getHeight(null);// 原图片高度 int dstMaxSize = 90;// 目标缩略图的最大宽度/高度,宽度与高度将按比例缩写 int dstWidth = srcWidth;// 缩略图宽度 int dstHeight = srcHeight;// 缩略图高度 float scale = 0; // 计算缩略图的宽和高 if (srcWidth > dstMaxSize) { dstWidth = dstMaxSize; scale = (float)srcWidth / (float)dstMaxSize; dstHeight = Math.round((float)srcHeight / scale); } srcHeight = dstHeight; if (srcHeight > dstMaxSize) { dstHeight = dstMaxSize; scale = (float)srcHeight / (float)dstMaxSize; dstWidth = Math.round((float)dstWidth / scale); } // 生成缩略图 tagImage = new BufferedImage(dstWidth, dstHeight, BufferedImage.TYPE_INT_RGB); tagImage.getGraphics().drawImage(srcImage, 0, 0, dstWidth, dstHeight, null); return tagImage; } finally { if (fileOutputStream != null) { try { fileOutputStream.close(); } catch (Exception e) { } fileOutputStream = null; } tagImage = null; srcImage = null; System.gc(); } } }