Support image based banners
Add ImageBanner class that generates color ASCII art based on an image file (banner.gif, banner.jpg or banner.png). See gh-4647
This commit is contained in:
		
							parent
							
								
									6550bb4cf1
								
							
						
					
					
						commit
						58d77ec961
					
				| 
						 | 
				
			
			@ -0,0 +1,249 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2015 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.springframework.boot;
 | 
			
		||||
 | 
			
		||||
import java.awt.Color;
 | 
			
		||||
import java.awt.Image;
 | 
			
		||||
 | 
			
		||||
import java.awt.image.BufferedImage;
 | 
			
		||||
 | 
			
		||||
import java.io.PrintStream;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Map.Entry;
 | 
			
		||||
 | 
			
		||||
import javax.imageio.ImageIO;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.ansi.AnsiPropertySource;
 | 
			
		||||
import org.springframework.core.env.Environment;
 | 
			
		||||
import org.springframework.core.env.MutablePropertySources;
 | 
			
		||||
import org.springframework.core.env.PropertyResolver;
 | 
			
		||||
import org.springframework.core.env.PropertySourcesPropertyResolver;
 | 
			
		||||
import org.springframework.core.io.Resource;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Banner implementation that prints ASCII art generated from an image resource
 | 
			
		||||
 * {@link Resource}.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Craig Burke
 | 
			
		||||
 */
 | 
			
		||||
public class ImageBanner implements Banner {
 | 
			
		||||
 | 
			
		||||
	private static final Log log = LogFactory.getLog(ImageBanner.class);
 | 
			
		||||
 | 
			
		||||
	private static final double RED_WEIGHT = 0.2126d;
 | 
			
		||||
	private static final double GREEN_WEIGHT = 0.7152d;
 | 
			
		||||
	private static final double BLUE_WEIGHT = 0.0722d;
 | 
			
		||||
 | 
			
		||||
	private static final int DEFAULT_MAX_WIDTH = 72;
 | 
			
		||||
	private static final double DEFAULT_ASPECT_RATIO = 0.5d;
 | 
			
		||||
	private static final boolean DEFAULT_DARK = false;
 | 
			
		||||
 | 
			
		||||
	private Resource image;
 | 
			
		||||
	private Map<String, Color> colors = new HashMap<String, Color>();
 | 
			
		||||
 | 
			
		||||
	public ImageBanner(Resource image) {
 | 
			
		||||
		Assert.notNull(image, "Image must not be null");
 | 
			
		||||
		Assert.isTrue(image.exists(), "Image must exist");
 | 
			
		||||
		this.image = image;
 | 
			
		||||
		colorsInit();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void colorsInit() {
 | 
			
		||||
		this.colors.put("BLACK", new Color(0, 0, 0));
 | 
			
		||||
		this.colors.put("RED", new Color(170, 0, 0));
 | 
			
		||||
		this.colors.put("GREEN", new Color(0, 170, 0));
 | 
			
		||||
		this.colors.put("YELLOW", new Color(170, 85, 0));
 | 
			
		||||
		this.colors.put("BLUE", new Color(0, 0, 170));
 | 
			
		||||
		this.colors.put("MAGENTA", new Color(170, 0, 170));
 | 
			
		||||
		this.colors.put("CYAN", new Color(0, 170, 170));
 | 
			
		||||
		this.colors.put("WHITE", new Color(170, 170, 170));
 | 
			
		||||
 | 
			
		||||
		this.colors.put("BRIGHT_BLACK", new Color(85, 85, 85));
 | 
			
		||||
		this.colors.put("BRIGHT_RED", new Color(255, 85, 85));
 | 
			
		||||
		this.colors.put("BRIGHT_GREEN", new Color(85, 255, 85));
 | 
			
		||||
		this.colors.put("BRIGHT_YELLOW", new Color(255, 255, 85));
 | 
			
		||||
		this.colors.put("BRIGHT_BLUE", new Color(85, 85, 255));
 | 
			
		||||
		this.colors.put("BRIGHT_MAGENTA", new Color(255, 85, 255));
 | 
			
		||||
		this.colors.put("BRIGHT_CYAN", new Color(85, 255, 255));
 | 
			
		||||
		this.colors.put("BRIGHT_WHITE", new Color(255, 255, 255));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
 | 
			
		||||
		String headlessProperty = System.getProperty("java.awt.headless");
 | 
			
		||||
		try {
 | 
			
		||||
			System.setProperty("java.awt.headless", "true");
 | 
			
		||||
			BufferedImage sourceImage = ImageIO.read(this.image.getInputStream());
 | 
			
		||||
 | 
			
		||||
			int maxWidth = environment.getProperty("banner.image.max-width",
 | 
			
		||||
					Integer.class, DEFAULT_MAX_WIDTH);
 | 
			
		||||
			Double aspectRatio = environment.getProperty("banner.image.aspect-ratio",
 | 
			
		||||
					Double.class, DEFAULT_ASPECT_RATIO);
 | 
			
		||||
			boolean invert = environment.getProperty("banner.image.dark", Boolean.class,
 | 
			
		||||
					DEFAULT_DARK);
 | 
			
		||||
 | 
			
		||||
			BufferedImage resizedImage = resizeImage(sourceImage, maxWidth, aspectRatio);
 | 
			
		||||
			String banner = imageToBanner(resizedImage, invert);
 | 
			
		||||
 | 
			
		||||
			PropertyResolver ansiResolver = getAnsiResolver();
 | 
			
		||||
			banner = ansiResolver.resolvePlaceholders(banner);
 | 
			
		||||
			out.println(banner);
 | 
			
		||||
		}
 | 
			
		||||
		catch (Exception ex) {
 | 
			
		||||
			log.warn("Image banner not printable: " + this.image + " (" + ex.getClass()
 | 
			
		||||
					+ ": '" + ex.getMessage() + "')", ex);
 | 
			
		||||
		}
 | 
			
		||||
		finally {
 | 
			
		||||
			System.setProperty("java.awt.headless", headlessProperty);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private PropertyResolver getAnsiResolver() {
 | 
			
		||||
		MutablePropertySources sources = new MutablePropertySources();
 | 
			
		||||
		sources.addFirst(new AnsiPropertySource("ansi", true));
 | 
			
		||||
		return new PropertySourcesPropertyResolver(sources);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private String imageToBanner(BufferedImage image, boolean dark) {
 | 
			
		||||
		StringBuilder banner = new StringBuilder();
 | 
			
		||||
 | 
			
		||||
		for (int y = 0; y < image.getHeight(); y++) {
 | 
			
		||||
			if (dark) {
 | 
			
		||||
				banner.append("${AnsiBackground.BLACK}");
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				banner.append("${AnsiBackground.DEFAULT}");
 | 
			
		||||
			}
 | 
			
		||||
			for (int x = 0; x < image.getWidth(); x++) {
 | 
			
		||||
				Color color = new Color(image.getRGB(x, y), false);
 | 
			
		||||
				banner.append(getFormatString(color, dark));
 | 
			
		||||
			}
 | 
			
		||||
			if (dark) {
 | 
			
		||||
				banner.append("${AnsiBackground.DEFAULT}");
 | 
			
		||||
			}
 | 
			
		||||
			banner.append("${AnsiColor.DEFAULT}\n");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return banner.toString();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protected String getFormatString(Color color, boolean dark) {
 | 
			
		||||
		String matchedColorName = null;
 | 
			
		||||
		Double minColorDistance = null;
 | 
			
		||||
 | 
			
		||||
		for (Entry<String, Color> colorOption : this.colors.entrySet()) {
 | 
			
		||||
			double distance = getColorDistance(color, colorOption.getValue());
 | 
			
		||||
 | 
			
		||||
			if (minColorDistance == null || distance < minColorDistance) {
 | 
			
		||||
				minColorDistance = distance;
 | 
			
		||||
				matchedColorName = colorOption.getKey();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return "${AnsiColor." + matchedColorName + "}" + getAsciiCharacter(color, dark);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static int getLuminance(Color color, boolean inverse) {
 | 
			
		||||
		double red = color.getRed();
 | 
			
		||||
		double green = color.getGreen();
 | 
			
		||||
		double blue = color.getBlue();
 | 
			
		||||
 | 
			
		||||
		double luminance;
 | 
			
		||||
 | 
			
		||||
		if (inverse) {
 | 
			
		||||
			luminance = (RED_WEIGHT * (255.0d - red)) + (GREEN_WEIGHT * (255.0d - green))
 | 
			
		||||
					+ (BLUE_WEIGHT * (255.0d - blue));
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			luminance = (RED_WEIGHT * red) + (GREEN_WEIGHT * green)
 | 
			
		||||
					+ (BLUE_WEIGHT * blue);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return (int) Math.ceil((luminance / 255.0d) * 100);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static char getAsciiCharacter(Color color, boolean dark) {
 | 
			
		||||
		double luminance = getLuminance(color, dark);
 | 
			
		||||
 | 
			
		||||
		if (luminance >= 90) {
 | 
			
		||||
			return ' ';
 | 
			
		||||
		}
 | 
			
		||||
		else if (luminance >= 80) {
 | 
			
		||||
			return '.';
 | 
			
		||||
		}
 | 
			
		||||
		else if (luminance >= 70) {
 | 
			
		||||
			return '*';
 | 
			
		||||
		}
 | 
			
		||||
		else if (luminance >= 60) {
 | 
			
		||||
			return ':';
 | 
			
		||||
		}
 | 
			
		||||
		else if (luminance >= 50) {
 | 
			
		||||
			return 'o';
 | 
			
		||||
		}
 | 
			
		||||
		else if (luminance >= 40) {
 | 
			
		||||
			return '&';
 | 
			
		||||
		}
 | 
			
		||||
		else if (luminance >= 30) {
 | 
			
		||||
			return '8';
 | 
			
		||||
		}
 | 
			
		||||
		else if (luminance >= 20) {
 | 
			
		||||
			return '#';
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			return '@';
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static double getColorDistance(Color color1, Color color2) {
 | 
			
		||||
		double redDelta = (color1.getRed() - color2.getRed()) * RED_WEIGHT;
 | 
			
		||||
		double greenDelta = (color1.getGreen() - color2.getGreen()) * GREEN_WEIGHT;
 | 
			
		||||
		double blueDelta = (color1.getBlue() - color2.getBlue()) * BLUE_WEIGHT;
 | 
			
		||||
 | 
			
		||||
		return Math.pow(redDelta, 2.0d) + Math.pow(greenDelta, 2.0d)
 | 
			
		||||
				+ Math.pow(blueDelta, 2.0d);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static BufferedImage resizeImage(BufferedImage sourceImage, int maxWidth,
 | 
			
		||||
			double aspectRatio) {
 | 
			
		||||
		int width;
 | 
			
		||||
		double resizeRatio;
 | 
			
		||||
		if (sourceImage.getWidth() > maxWidth) {
 | 
			
		||||
			resizeRatio = (double) maxWidth / (double) sourceImage.getWidth();
 | 
			
		||||
			width = maxWidth;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			resizeRatio = 1.0d;
 | 
			
		||||
			width = sourceImage.getWidth();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int height = (int) (Math.ceil(resizeRatio * aspectRatio
 | 
			
		||||
				* (double) sourceImage.getHeight()));
 | 
			
		||||
		Image image = sourceImage.getScaledInstance(width, height, Image.SCALE_DEFAULT);
 | 
			
		||||
 | 
			
		||||
		BufferedImage resizedImage = new BufferedImage(image.getWidth(null),
 | 
			
		||||
				image.getHeight(null), BufferedImage.TYPE_INT_RGB);
 | 
			
		||||
 | 
			
		||||
		resizedImage.getGraphics().drawImage(image, 0, 0, null);
 | 
			
		||||
		return resizedImage;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -140,6 +140,7 @@ import org.springframework.web.context.support.StandardServletEnvironment;
 | 
			
		|||
 * @author Christian Dupuis
 | 
			
		||||
 * @author Stephane Nicoll
 | 
			
		||||
 * @author Jeremy Rickard
 | 
			
		||||
 * @author Craig Burke
 | 
			
		||||
 * @see #run(Object, String[])
 | 
			
		||||
 * @see #run(Object[], String[])
 | 
			
		||||
 * @see #SpringApplication(Object...)
 | 
			
		||||
| 
						 | 
				
			
			@ -569,9 +570,27 @@ public class SpringApplication {
 | 
			
		|||
		if (this.banner != null) {
 | 
			
		||||
			return this.banner;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Resource image = getBannerImage(environment, resourceLoader);
 | 
			
		||||
		if (image.exists()) {
 | 
			
		||||
			return new ImageBanner(image);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return DEFAULT_BANNER;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private Resource getBannerImage(Environment environment, ResourceLoader resourceLoader) {
 | 
			
		||||
		String imageLocation = environment.getProperty("banner.image", "banner.gif");
 | 
			
		||||
		Resource image = resourceLoader.getResource(imageLocation);
 | 
			
		||||
		if (!image.exists()) {
 | 
			
		||||
			image = resourceLoader.getResource("banner.jpg");
 | 
			
		||||
		}
 | 
			
		||||
		if (!image.exists()) {
 | 
			
		||||
			image = resourceLoader.getResource("banner.png");
 | 
			
		||||
		}
 | 
			
		||||
		return image;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private String createStringFromBanner(Banner banner, Environment environment)
 | 
			
		||||
			throws UnsupportedEncodingException {
 | 
			
		||||
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,239 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2014 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.springframework.boot;
 | 
			
		||||
 | 
			
		||||
import java.io.ByteArrayOutputStream;
 | 
			
		||||
import java.io.PrintStream;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.ansi.AnsiBackground;
 | 
			
		||||
import org.springframework.boot.ansi.AnsiColor;
 | 
			
		||||
import org.springframework.boot.ansi.AnsiElement;
 | 
			
		||||
import org.springframework.boot.ansi.AnsiOutput;
 | 
			
		||||
import org.springframework.core.env.ConfigurableEnvironment;
 | 
			
		||||
import org.springframework.core.env.MapPropertySource;
 | 
			
		||||
import org.springframework.core.io.ClassPathResource;
 | 
			
		||||
import org.springframework.core.io.Resource;
 | 
			
		||||
import org.springframework.mock.env.MockEnvironment;
 | 
			
		||||
 | 
			
		||||
import static org.hamcrest.Matchers.containsString;
 | 
			
		||||
import static org.hamcrest.Matchers.equalTo;
 | 
			
		||||
import static org.hamcrest.Matchers.startsWith;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.assertThat;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for {@link ImageBanner}.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Craig Burke
 | 
			
		||||
 */
 | 
			
		||||
public class ImageBannerTests {
 | 
			
		||||
 | 
			
		||||
	private static final String IMAGE_BANNER_BLACK_AND_WHITE = "banners/black-and-white.gif";
 | 
			
		||||
	private static final String IMAGE_BANNER_LARGE = "banners/large.gif";
 | 
			
		||||
	private static final String IMAGE_BANNER_ALL_COLORS = "banners/colors.gif";
 | 
			
		||||
	private static final String IMAGE_BANNER_GRADIENT = "banners/gradient.gif";
 | 
			
		||||
 | 
			
		||||
	private static final String BACKGROUND_DEFAULT_ANSI = getAnsiOutput(AnsiBackground.DEFAULT);
 | 
			
		||||
	private static final String BACKGROUND_DARK_ANSI = getAnsiOutput(AnsiBackground.BLACK);
 | 
			
		||||
 | 
			
		||||
	private static final char HIGH_LUMINANCE_CHARACTER = ' ';
 | 
			
		||||
	private static final char LOW_LUMINANCE_CHARACTER = '@';
 | 
			
		||||
 | 
			
		||||
	private static Map<String, Object> properties;
 | 
			
		||||
 | 
			
		||||
	@Before
 | 
			
		||||
	public void setup() {
 | 
			
		||||
		AnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);
 | 
			
		||||
		properties = new HashMap<String, Object>();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderDefaultBackground() {
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_BLACK_AND_WHITE);
 | 
			
		||||
 | 
			
		||||
		assertThat(banner, startsWith(BACKGROUND_DEFAULT_ANSI));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderDarkBackground() {
 | 
			
		||||
		setDark(true);
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_BLACK_AND_WHITE);
 | 
			
		||||
 | 
			
		||||
		assertThat(banner, startsWith(BACKGROUND_DARK_ANSI));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderWhiteCharactersWithColors() {
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_BLACK_AND_WHITE);
 | 
			
		||||
		String expectedFirstLine = getAnsiOutput(AnsiColor.BRIGHT_WHITE)
 | 
			
		||||
				+ HIGH_LUMINANCE_CHARACTER;
 | 
			
		||||
 | 
			
		||||
		assertThat(banner, containsString(expectedFirstLine));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderWhiteCharactersOnDarkBackground() {
 | 
			
		||||
		setDark(true);
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_BLACK_AND_WHITE);
 | 
			
		||||
		String expectedFirstLine = getAnsiOutput(AnsiColor.BRIGHT_WHITE)
 | 
			
		||||
				+ LOW_LUMINANCE_CHARACTER;
 | 
			
		||||
 | 
			
		||||
		assertThat(banner, containsString(expectedFirstLine));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderBlackCharactersOnDefaultBackground() {
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_BLACK_AND_WHITE);
 | 
			
		||||
		String blackCharacter = getAnsiOutput(AnsiColor.BLACK) + LOW_LUMINANCE_CHARACTER;
 | 
			
		||||
 | 
			
		||||
		assertThat(banner, containsString(blackCharacter));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderBlackCharactersOnDarkBackground() {
 | 
			
		||||
		setDark(true);
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_BLACK_AND_WHITE);
 | 
			
		||||
		String blackCharacter = getAnsiOutput(AnsiColor.BLACK) + HIGH_LUMINANCE_CHARACTER;
 | 
			
		||||
 | 
			
		||||
		assertThat(banner, containsString(blackCharacter));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderBannerWithAllColors() {
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_ALL_COLORS);
 | 
			
		||||
 | 
			
		||||
		assertThat("Banner contains BLACK", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.BLACK)));
 | 
			
		||||
		assertThat("Banner contains RED", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.RED)));
 | 
			
		||||
		assertThat("Banner contains GREEN", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.GREEN)));
 | 
			
		||||
		assertThat("Banner contains YELLOW", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.YELLOW)));
 | 
			
		||||
		assertThat("Banner contains BLUE", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.BLUE)));
 | 
			
		||||
		assertThat("Banner contains MAGENTA", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.MAGENTA)));
 | 
			
		||||
		assertThat("Banner contains CYAN", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.CYAN)));
 | 
			
		||||
		assertThat("Banner contains WHITE", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.WHITE)));
 | 
			
		||||
 | 
			
		||||
		assertThat("Banner contains BRIGHT_BLACK", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.BRIGHT_BLACK)));
 | 
			
		||||
		assertThat("Banner contains BRIGHT_RED", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.BRIGHT_RED)));
 | 
			
		||||
		assertThat("Banner contains BRIGHT_GREEN", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.BRIGHT_GREEN)));
 | 
			
		||||
		assertThat("Banner contains BRIGHT_YELLOW", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.BRIGHT_YELLOW)));
 | 
			
		||||
		assertThat("Banner contains BRIGHT_BLUE", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.BRIGHT_BLUE)));
 | 
			
		||||
		assertThat("Banner contains BRIGHT_MAGENTA", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.BRIGHT_MAGENTA)));
 | 
			
		||||
		assertThat("Banner contains BRIGHT_CYAN", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.BRIGHT_CYAN)));
 | 
			
		||||
		assertThat("Banner contains BRIGHT_WHITE", banner,
 | 
			
		||||
				containsString(getAnsiOutput(AnsiColor.BRIGHT_WHITE)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderSimpleGradient() {
 | 
			
		||||
		AnsiOutput.setEnabled(AnsiOutput.Enabled.NEVER);
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_GRADIENT);
 | 
			
		||||
		String expectedResult = "@#8&o:*. ";
 | 
			
		||||
 | 
			
		||||
		assertThat(banner, startsWith(expectedResult));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderBannerWithDefaultAspectRatio() {
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_BLACK_AND_WHITE);
 | 
			
		||||
		int bannerHeight = getBannerHeight(banner);
 | 
			
		||||
 | 
			
		||||
		assertThat(bannerHeight, equalTo(2));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderBannerWithCustomAspectRatio() {
 | 
			
		||||
		setAspectRatio(1.0d);
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_BLACK_AND_WHITE);
 | 
			
		||||
		int bannerHeight = getBannerHeight(banner);
 | 
			
		||||
 | 
			
		||||
		assertThat(bannerHeight, equalTo(4));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderLargeBanner() {
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_LARGE);
 | 
			
		||||
		int bannerWidth = getBannerWidth(banner);
 | 
			
		||||
 | 
			
		||||
		assertThat(bannerWidth, equalTo(72));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void renderLargeBannerWithACustomWidth() {
 | 
			
		||||
		setMaxWidth(60);
 | 
			
		||||
		String banner = printBanner(IMAGE_BANNER_LARGE);
 | 
			
		||||
		int bannerWidth = getBannerWidth(banner);
 | 
			
		||||
 | 
			
		||||
		assertThat(bannerWidth, equalTo(60));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private int getBannerHeight(String banner) {
 | 
			
		||||
		return banner.split("\n").length;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private int getBannerWidth(String banner) {
 | 
			
		||||
		String strippedBanner = banner.replaceAll("\u001B\\[.*?m", "");
 | 
			
		||||
		String firstLine = strippedBanner.split("\n")[0];
 | 
			
		||||
		return firstLine.length();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static String getAnsiOutput(AnsiElement ansi) {
 | 
			
		||||
		return "\u001B[" + ansi.toString() + "m";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void setDark(boolean dark) {
 | 
			
		||||
		properties.put("banner.image.dark", dark);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void setMaxWidth(int maxWidth) {
 | 
			
		||||
		properties.put("banner.image.max-width", maxWidth);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void setAspectRatio(double aspectRatio) {
 | 
			
		||||
		properties.put("banner.image.aspect-ratio", aspectRatio);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private String printBanner(String imagePath) {
 | 
			
		||||
		Resource image = new ClassPathResource(imagePath);
 | 
			
		||||
		ImageBanner banner = new ImageBanner(image);
 | 
			
		||||
		ConfigurableEnvironment environment = new MockEnvironment();
 | 
			
		||||
		environment.getPropertySources().addLast(
 | 
			
		||||
				new MapPropertySource("testConfig", properties));
 | 
			
		||||
		ByteArrayOutputStream out = new ByteArrayOutputStream();
 | 
			
		||||
		banner.printBanner(environment, getClass(), new PrintStream(out));
 | 
			
		||||
		return out.toString();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -19,8 +19,10 @@ package org.springframework.boot;
 | 
			
		|||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.LinkedHashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.concurrent.atomic.AtomicReference;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -66,6 +68,7 @@ import org.springframework.core.env.MapPropertySource;
 | 
			
		|||
import org.springframework.core.env.PropertySource;
 | 
			
		||||
import org.springframework.core.env.StandardEnvironment;
 | 
			
		||||
import org.springframework.core.io.DefaultResourceLoader;
 | 
			
		||||
import org.springframework.core.io.Resource;
 | 
			
		||||
import org.springframework.core.io.ResourceLoader;
 | 
			
		||||
import org.springframework.test.context.support.TestPropertySourceUtils;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
| 
						 | 
				
			
			@ -90,6 +93,7 @@ import static org.mockito.Mockito.verify;
 | 
			
		|||
 * @author Christian Dupuis
 | 
			
		||||
 * @author Stephane Nicoll
 | 
			
		||||
 * @author Jeremy Rickard
 | 
			
		||||
 * @author Craig Burke
 | 
			
		||||
 */
 | 
			
		||||
public class SpringApplicationTests {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -191,6 +195,32 @@ public class SpringApplicationTests {
 | 
			
		|||
				.startsWith(String.format("Running a Test!%n%n123456"));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void textBannerTakesPrecedence() throws Exception {
 | 
			
		||||
		SpringApplication application = new SpringApplication(ExampleConfig.class);
 | 
			
		||||
		BannerResourceLoaderStub resourceLoader = new BannerResourceLoaderStub();
 | 
			
		||||
		resourceLoader.addResource("banner.gif", "banners/black-and-white.gif");
 | 
			
		||||
		resourceLoader.addResource("banner.txt", "banners/foobar.txt");
 | 
			
		||||
 | 
			
		||||
		application.setWebEnvironment(false);
 | 
			
		||||
		application.setResourceLoader(resourceLoader);
 | 
			
		||||
		application.run();
 | 
			
		||||
 | 
			
		||||
		assertThat(this.output.toString()).startsWith("Foo Bar");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void imageBannerLoads() throws Exception {
 | 
			
		||||
		SpringApplication application = new SpringApplication(ExampleConfig.class);
 | 
			
		||||
		BannerResourceLoaderStub resourceLoader = new BannerResourceLoaderStub();
 | 
			
		||||
		resourceLoader.addResource("banner.gif", "banners/black-and-white.gif");
 | 
			
		||||
		application.setWebEnvironment(false);
 | 
			
		||||
		application.setResourceLoader(resourceLoader);
 | 
			
		||||
		application.run();
 | 
			
		||||
 | 
			
		||||
		assertThat(this.output.toString()).startsWith("@");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void logsNoActiveProfiles() throws Exception {
 | 
			
		||||
		SpringApplication application = new SpringApplication(ExampleConfig.class);
 | 
			
		||||
| 
						 | 
				
			
			@ -1089,4 +1119,31 @@ public class SpringApplicationTests {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static class BannerResourceLoaderStub extends DefaultResourceLoader {
 | 
			
		||||
 | 
			
		||||
		private Map<String, String> resources = new HashMap<String, String>();
 | 
			
		||||
		Resource notFoundResource;
 | 
			
		||||
 | 
			
		||||
		BannerResourceLoaderStub() {
 | 
			
		||||
			this.notFoundResource = super.getResource("classpath:foo/bar/foobar");
 | 
			
		||||
			assert !this.notFoundResource.exists();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void addResource(String file, String realPath) {
 | 
			
		||||
			this.resources.put(file, realPath);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public Resource getResource(String s) {
 | 
			
		||||
			if (this.resources.containsKey(s)) {
 | 
			
		||||
				return super.getResource("classpath:" + this.resources.get(s));
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				return this.notFoundResource;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 44 B  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 95 B  | 
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
Foo Bar
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 817 B  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 142 B  | 
		Loading…
	
		Reference in New Issue