Springboot 系列(八)动态Banner与图片转字符图案的手动实现

使用过 Springboot 的对上面这个图案肯定不会陌生,Springboot 启动的同时会打印上面的图案,并带有版本号。查看官方文档可以找到关于 banner 的描述

The banner that is printed on start up can be changed by adding a banner.txt file to your classpath or by setting the spring.banner.location property to the location of such a file. If the file has an encoding other than UTF-8, you can set spring.banner.charset. In addition to a text file, you can also add a banner.gif, banner.jpg, or banner.png image file to your classpath or set the spring.banner.image.location property. Images are converted into an ASCII art representation and printed above any text banner.

就不翻译了,直接有道翻译贴过来看个大概意思。

可以通过向类路径中添加一个banner.txt文件或设置spring.banner来更改在start up上打印的banner。属性指向此类文件的位置。如果文件的编码不是UTF-8,那么可以设置spring.banner.charset。除了文本文件,还可以添加横幅。将gif、banner.jpg或banner.png图像文件保存到类路径或设置spring.banner.image。位置属性。图像被转换成ASCII艺术形式,并打印在任何文本横幅上面。

1. 自定义 banner

根据官方的描述,可以在类路径中自定义 banner 图案,我们进行尝试在放 resouce 目录下新建文件 banner.txt 并写入内容(在线字符生成)。

     (_)
  _ __  _ _   _ _ __ ___   ___   ___
 | ‘_ \| | | | | ‘_ ` _ \ / _ \ / _  | | | | | |_| | | | | | | (_) | (_) |
 |_| |_|_|\__,_|_| |_| |_|\___/ \___/ 版本:${spring-boot.formatted-version}

启动 Springboot 在控制台看到下面的输出。

     (_)
  _ __  _ _   _ _ __ ___   ___   ___
 | ‘_ \| | | | | ‘_ ` _ \ / _ \ / _  | | | | | |_| | | | | | | (_) | (_) |
 |_| |_|_|\__,_|_| |_| |_|\___/ \___/ 版本:(v2.1.3.RELEASE)
2019-02-25 14:00:31.289  INFO 12312 --- [           main] net.codingme.banner.BannerApplication    : Starting BannerApplication on LAPTOP-L1S5MKTA with PID 12312 (D:\IdeaProjectMy\springboot-git\springboot-banner\target\classes started by Niu in D:\IdeaProjectMy\springboot-git\springboot-banner)
2019-02-25 14:00:31.291  INFO 12312 --- [           main] net.codingme.banner.BannerApplication    : No active profile set, falling back to default profiles: default
2019-02-25 14:00:32.087  INFO 12312 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)

发现自定义 banner 已经生效了,官方文档的介绍里说还可以放置图片,下面放置图片 banner.jpg 测试。

网上随便找了一个图片。

再次启动观察输出。

Springboot 把图案转成了 ASCII 图案。

2. ASCII 图案生成原理

看了上面的例子,发现 Springboot 可以把图片转换成 ASCII 图案,那么它是怎么做的呢?我们或许可以想象出一个大概流程。

  1. 获取图片。
  2. 遍历图片像素点。
  3. 分析像素点,每个像素点根据颜色深度得出一个值,根据明暗度匹配不同的字符。
  4. 输出图案。

Springboot 对图片 banner 的处理到底是不是我们上面想想的那样呢?直接去源码中寻找答案。

/** 位置:org.springframework.boot.SpringApplicationBannerPrinter */
//方法1:
public Banner print(Environment environment, Class<?> sourceClass, Log logger) {
        // 获取 banner  调用方法记为2
        Banner banner = getBanner(environment);
        try {
            logger.info(createStringFromBanner(banner, environment, sourceClass));
        }
        catch (UnsupportedEncodingException ex) {
            logger.warn("Failed to create String for banner", ex);
        }
        // 打印 banner
        return new PrintedBanner(banner, sourceClass);
}
// 方法2
private Banner getBanner(Environment environment) {
        Banners banners = new Banners();
        // 获取图片banner,我们只关注这个,调用方法记为3
        banners.addIfNotNull(getImageBanner(environment));
        banners.addIfNotNull(getTextBanner(environment));
        if (banners.hasAtLeastOneBanner()) {
            return banners;
        }
        if (this.fallbackBanner != null) {
            return this.fallbackBanner;
        }
        return DEFAULT_BANNER;
    }
// 方法3
/** 获取自定义banner文件信息 */
private Banner getImageBanner(Environment environment) {
    // BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
        String location = environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY);
        if (StringUtils.hasLength(location)) {
            Resource resource = this.resourceLoader.getResource(location);
            return resource.exists() ? new ImageBanner(resource) : null;
        }
        // IMAGE_EXTENSION = { "gif", "jpg", "png" };
        for (String ext : IMAGE_EXTENSION) {
            Resource resource = this.resourceLoader.getResource("banner." + ext);
            if (resource.exists()) {
                return new ImageBanner(resource);
            }
        }
        return null;
}

上面是寻找自定义图片 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 字符图案。

思路如下:

  1. 图片大小缩放,调整到合适大小。
  2. 遍历图片像素。
  3. 获取图片像素点亮度(RGB颜色通过公式可以得到亮度数值)。
  4. 匹配字符。
  5. 输出图案。

上面的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 www.codingme.net
 * @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();
        }
    }
}

还是拿上面的 Google log 图片作为实验对象,运行得到字符图案输出。

文章代码已经上传到 GitHub Spring Boot

<完>

欢迎点赞关注!

本文原发于个人博客:https://www.codingme.net 转载请注明出处

原文地址:https://www.cnblogs.com/niumoo/p/10434746.html

时间: 2024-08-29 10:14:47

Springboot 系列(八)动态Banner与图片转字符图案的手动实现的相关文章

katalon系列八:Katalon Studio图片识别

Katalon Studio自带集成了图片识别功能,有2个比较有用的图片识别相关的命令:Wait For Image Present和Click Image.这里重点讲下Click Image命令: 当你需要在浏览器里去操作非浏览器元素,比如IE的保存调的就是Windows的控件了: 当你无法定位某个元素,但其却有比较明显的图片特征时:   1.先截取你要定位的元素,比如我这里截图的是百度的LOGO     2.创建一个图片对象元素:右击左侧文件管理的Object Repository--New

SpringBoot系列八:SpringBoot整合消息服务(SpringBoot 整合 ActiveMQ、SpringBoot 整合 RabbitMQ、SpringBoot 整合 Kafka)

https://www.cnblogs.com/xuyiqing/p/10851859.html https://www.cnblogs.com/leeSmall/p/8721556.html https://www.cnblogs.com/linyufeng/p/9885645.html 原文地址:https://www.cnblogs.com/418836844qqcom/p/11540020.html

Spring boot 2.0 新特性之动态 Banner

Spring Boot 2.0 提供了很多新特性,其中就有一个小彩蛋:动态 Banner,今天我们就先拿这个来尝尝鲜. 配置依赖 使用 Spring Boot 2.0 首先需要将项目依赖包替换为刚刚发布的 2.0 RELEASE,现在网站https://start.spring.io/也将 Spring Boot 2.0 设置为默认版本. <parent> <groupId>org.springframework.boot</groupId> <artifactI

Cocos2d-x 系列八之Box2d入门

既然已有了cocos2d-x,为什么还要Box2d呢,是因为cocos2d-x作为一个图像引擎,只是用于显示图像,图像之间可以任意的重合,如果想要做到类物理学的碰撞等运动效果,就需要用到Box2d这个物理引擎用来模仿物理世界中的物体: 本讲主要简单讲述如何创建动态物体,静态物体,漂浮物体,以及它们与图像的绑定: 下面直接通过一个例子来看三种物体的创建方法: 首先需要说明的一点是:在Box2d中,使用的单位是米,而不是像素,所以,在进行位置转换的时候,需要按比例缩放,Box2d中,比较理想的距离大

SQL Server 2008空间数据应用系列八:基于Bing Maps(Silverlight)的空间数据存储

原文:SQL Server 2008空间数据应用系列八:基于Bing Maps(Silverlight)的空间数据存储 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft SQL Server 2008 R2调测. 2.具备 Transact-SQL 编程经验和使用 SQL Server Management Studio 的经验. 3.具有使用 Microsoft Visual Studio 进行 Microsoft .NET Framework开发的经验. 4.具有

android图像处理系列之四--给图片添加边框(上)

图片处理时,有时需要为图片加一些边框,下面介绍一种为图片添加简单边框的方法. 基本思路是:将边框图片裁剪成八张小图片(图片大小最好一致,不然后面处理会很麻烦),分别对应左上角,左边,左下角,下边,右下角,右边,右上角,上边,其中左右上下只需要一个有效长度,就像重写水平进度条一样,只需要一个有效的长度,然后平铺,就达到了最后想要的效果,不错,左右上下边采用的也是这样的思路.也可以将八张图片组合在一起,然后读取整张图片,用代码裁剪,下面会给出相应的代码.下面的代码主要是给出第一种方法,后一种给出代码

android图像处理系列之四-- 给图片添加边框(上)

图片处理时,有时需要为图片加一些边框,下面介绍一种为图片添加简单边框的方法. 基本思路是:将边框图片裁剪成八张小图片(图片大小最好一致,不然后面处理会很麻烦),分别对应左上角,左边,左下角,下边,右下角,右边,右上角,上边,其中左右上下只需要一个有效长度,就像重写水平进度条一样,只需要一个有效的长度,然后平铺,就达到了最后想要的效果,不错,左右上下边采用的也是这样的思路.也可以将八张图片组合在一起,然后读取整张图片,用代码裁剪,下面会给出相应的代码.下面的代码主要是给出第一种方法,后一种给出代码

Spring Boot 2.0(一):Spring Boot 2.0尝鲜-动态 Banner

Spring Boot 2.0 提供了很多新特性,其中就有一个小彩蛋:动态 Banner,今天我们就先拿这个来尝尝鲜 Spring Boot 更换 Banner 我们先来回顾一下在 Spring Boot 1.0 中如何更换启动 Banner,其实都很简单,只需要在src/main/resources路径下新建一个banner.txt文件,banner.txt中填写好需要打印的字符串内容即可. 一般情况下,我们会借助第三方工具帮忙转化内容,如网站http://www.network-scienc

SpringBoot系列教程web篇之404、500异常页面配置

接着前面几篇web处理请求的博文,本文将说明,当出现异常的场景下,如404请求url不存在,,403无权,500服务器异常时,我们可以如何处理 原文友链: SpringBoot系列教程web篇之404.500异常页面配置 I. 环境搭建 首先得搭建一个web应用才有可能继续后续的测试,借助SpringBoot搭建一个web应用属于比较简单的活; 创建一个maven项目,pom文件如下 <parent> <groupId>org.springframework.boot</gr