Add block pixel mode support for image banners
Add support for a `spring.banner.image.pixelmode` property which can be set to `block` to use unicode block characters when rendering image banners. Closes gh-18301
This commit is contained in:
parent
18396a3dc3
commit
303974fde9
@ -62,12 +62,6 @@ public class ImageBanner implements Banner {
|
||||
|
||||
private static final double[] RGB_WEIGHT = { 0.2126d, 0.7152d, 0.0722d };
|
||||
|
||||
private static final char[] PIXEL = { ' ', '.', '*', ':', 'o', '&', '8', '#', '@' };
|
||||
|
||||
private static final int LUMINANCE_INCREMENT = 10;
|
||||
|
||||
private static final int LUMINANCE_START = LUMINANCE_INCREMENT * PIXEL.length;
|
||||
|
||||
private final Resource image;
|
||||
|
||||
public ImageBanner(Resource image) {
|
||||
@ -104,12 +98,13 @@ public class ImageBanner implements Banner {
|
||||
int margin = getProperty(environment, "margin", Integer.class, 2);
|
||||
boolean invert = getProperty(environment, "invert", Boolean.class, false);
|
||||
BitDepth bitDepth = getBitDepthProperty(environment);
|
||||
PixelMode pixelMode = getPixelModeProperty(environment);
|
||||
Frame[] frames = readFrames(width, height);
|
||||
for (int i = 0; i < frames.length; i++) {
|
||||
if (i > 0) {
|
||||
resetCursor(frames[i - 1].getImage(), out);
|
||||
}
|
||||
printBanner(frames[i].getImage(), margin, invert, bitDepth, out);
|
||||
printBanner(frames[i].getImage(), margin, invert, bitDepth, pixelMode, out);
|
||||
sleep(frames[i].getDelayTime());
|
||||
}
|
||||
}
|
||||
@ -119,6 +114,11 @@ public class ImageBanner implements Banner {
|
||||
return (bitDepth != null) ? BitDepth.of(bitDepth) : BitDepth.FOUR;
|
||||
}
|
||||
|
||||
private PixelMode getPixelModeProperty(Environment environment) {
|
||||
String pixelMode = getProperty(environment, "pixelmode", String.class, null);
|
||||
return (pixelMode != null) ? PixelMode.valueOf(pixelMode.trim().toUpperCase()) : PixelMode.TEXT;
|
||||
}
|
||||
|
||||
private <T> T getProperty(Environment environment, String name, Class<T> targetType, T defaultValue) {
|
||||
return environment.getProperty(PROPERTY_PREFIX + name, targetType, defaultValue);
|
||||
}
|
||||
@ -197,7 +197,8 @@ public class ImageBanner implements Banner {
|
||||
out.print("\033[" + lines + "A\r");
|
||||
}
|
||||
|
||||
private void printBanner(BufferedImage image, int margin, boolean invert, BitDepth bitDepth, PrintStream out) {
|
||||
private void printBanner(BufferedImage image, int margin, boolean invert, BitDepth bitDepth, PixelMode pixelMode,
|
||||
PrintStream out) {
|
||||
AnsiElement background = invert ? AnsiBackground.BLACK : AnsiBackground.DEFAULT;
|
||||
out.print(AnsiOutput.encode(AnsiColor.DEFAULT));
|
||||
out.print(AnsiOutput.encode(background));
|
||||
@ -216,7 +217,7 @@ public class ImageBanner implements Banner {
|
||||
out.print(AnsiOutput.encode(ansiColor));
|
||||
lastColor = ansiColor;
|
||||
}
|
||||
out.print(getAsciiPixel(color, invert));
|
||||
out.print(getAsciiPixel(color, invert, pixelMode));
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
@ -225,14 +226,17 @@ public class ImageBanner implements Banner {
|
||||
out.println();
|
||||
}
|
||||
|
||||
private char getAsciiPixel(Color color, boolean dark) {
|
||||
private char getAsciiPixel(Color color, boolean dark, PixelMode pixelMode) {
|
||||
char[] pixels = pixelMode.getPixels();
|
||||
int increment = (10 / pixels.length) * 10;
|
||||
int start = increment * pixels.length;
|
||||
double luminance = getLuminance(color, dark);
|
||||
for (int i = 0; i < PIXEL.length; i++) {
|
||||
if (luminance >= (LUMINANCE_START - (i * LUMINANCE_INCREMENT))) {
|
||||
return PIXEL[i];
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
if (luminance >= (start - (i * increment))) {
|
||||
return pixels[i];
|
||||
}
|
||||
}
|
||||
return PIXEL[PIXEL.length - 1];
|
||||
return pixels[pixels.length - 1];
|
||||
}
|
||||
|
||||
private int getLuminance(Color color, boolean inverse) {
|
||||
@ -277,4 +281,31 @@ public class ImageBanner implements Banner {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pixel modes supported by the image banner.
|
||||
*/
|
||||
public enum PixelMode {
|
||||
|
||||
/**
|
||||
* Use text chars for pixels.
|
||||
*/
|
||||
TEXT(' ', '.', '*', ':', 'o', '&', '8', '#', '@'),
|
||||
|
||||
/**
|
||||
* Use unicode block chars for pixels.
|
||||
*/
|
||||
BLOCK(' ', '\u2591', '\u2592', '\u2593', '\u2588');
|
||||
|
||||
private char[] pixels;
|
||||
|
||||
PixelMode(char... pixels) {
|
||||
this.pixels = pixels;
|
||||
}
|
||||
|
||||
char[] getPixels() {
|
||||
return this.pixels;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -53,6 +53,12 @@
|
||||
"description": "The bit depth to use for ANSI colors. Supported values are 4 (16 color) or 8 (256 color).",
|
||||
"defaultValue": 4
|
||||
},
|
||||
{
|
||||
"name": "spring.banner.image.pixelmode",
|
||||
"type": "org.springframework.boot.ImageBanner$PixelMode",
|
||||
"description": "The pixel mode to use when rendering the image.",
|
||||
"defaultValue": "TEXT"
|
||||
},
|
||||
{
|
||||
"name": "debug",
|
||||
"type": "java.lang.Boolean",
|
||||
|
@ -179,6 +179,14 @@ class ImageBannerTests {
|
||||
assertThat(banner.contains(AnsiOutput.encode(Ansi8BitColor.foreground(37))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void printBannerWhenPixelModeIsBlockShouldRenderBlocks() {
|
||||
AnsiOutput.setEnabled(AnsiOutput.Enabled.NEVER);
|
||||
String banner = printBanner("gradient.gif", "spring.banner.image.width=6", "spring.banner.image.margin=0",
|
||||
"spring.banner.image.pixelmode=block");
|
||||
assertThat(banner).contains("\u2588\u2593\u2592\u2591 ");
|
||||
}
|
||||
|
||||
private int getBannerHeight(String banner) {
|
||||
return banner.split(System.lineSeparator()).length - 3;
|
||||
}
|
||||
|
@ -0,0 +1,2 @@
|
||||
spring.banner.image.bitdepth=8
|
||||
spring.banner.image.pixelmode=block
|
Loading…
x
Reference in New Issue
Block a user