quarkus
quarkus copied to clipboard
Support graphical banners
Support graphical banners if the banner file name ends with .png
and the terminal supports graphics.
Why?
It looks really cool.
And, I needed a break from more difficult work. This has been on my back burner for years so I thought I'd put something together to see if it was feasible, and it is!
How?
Many modern terminals support inline image output. It's a matter of image encoding and escape codes, pretty much. There are multiple ways to transfer images to the terminal including temporary files and shared memory, but I opted for the simplest and most direct route: translating the image directly into base64 and transmitting it in line.
What works?
Any PNG image should work (including transparent). The image is currently hard-coded to have a height of 4 character rows. The width is then calculated based on the aspect ratio of the image. The image is scaled to fit these dimensions.
If the terminal is detected to not support graphics, the image is not displayed (otherwise it appears as a huge blob of base64 text).
What doesn't work?
Any kind of dark/light mode detection. Best results will be with images which look good on any background. In my test (see image) I just used a Quarkus "dark mode" logo.
My terminal of choice, kitty
, does not properly compute the aspect ratio automatically as it should, so I compute the columns/rows aspect ratio by hand using an estimate of 1.8
for the font height-to-width aspect ratio. It looks OK on my terminal but will probably look weird if you use a different font than I do. I'll probably remove this hack once the bug is fixed. The bug is kitty#7380. Once this is solved, using ImageIO
would no longer be needed for analyzing the image.
More?
There are all kinds of things we can do with terminal image support, up to and including a complete graphical terminal-based console. But, printing a banner is spiffy enough for now I think.
Several other image types could easily be supported as well. I think PNG is the logical starting point though due to its support for transparency.
Glamorous :)
Cool :)
It looks really cool.
This is the coolest thing I've seen in a while!
Holy crap, that's amazing!
@dmlloyd I've tested locally and it looks great. What's missing to make this PR Ready for Review?
Interesting that it doesn't work with quarkus dev
A few things (I'll make it a checklist):
- [x] ~~Wait for a new release of
kitty
to be out for a little while and drop theImageIO
stuff~~ (This was replaced by configuration options to override the scale factor) - [x] Have a fallback so if graphics are not supported, it can fall back to
xxxx.txt
fromxxxx.png
- [ ] Maybe some kind of dark mode detection? (This is kind of hard/expensive to do though)
- [x] Maybe columns/rows configuration?
- [ ] Come up with a nice default banner that looks good on both light and dark screens (maybe the default Quarkus logo, optimized for dark mode but with black outlines around the white letters so they are visible on a light screen? Maybe @insectengine has an idea...)
Neat.
Is the idea to have a default PNG or just to let users provide one? Asking sinde at least historically for me the PNG rendering makes console output slower so would need convincing to make it the default.
Anyone tested this on windows and when running inside a container yet ? :)
So I love this, but I have a suggestion. It'd be cute to auto-convert the png to ascii art for the cases where this doesn't work. That saves people having to provide a fallback, and ascii art is just awesome anyway.
That will be a part of boot time that users may use for comparisons though.
That will be a part of boot time that users may use for comparisons though.
The conversion could be build-time, right? And we just package up the fallback.txt.
Neat.
Is the idea to have a default PNG or just to let users provide one?
As stated above, I think it would be nifty to have a default one.
Asking since at least historically for me the PNG rendering makes console output slower so would need convincing to make it the default.
Yeah it'll definitely have some amount of overhead, but I never observed anything I would call "slow" using kitty
even on my 10-year-old Linux workhorse.
The potential performance impacts would include:
- Data transfer - I transfer the image in-line presently, but it's also possible to write the image to a file and tell the terminal to find it there. Obviously this won't work across an SSH link without some kind of magic though. There's also a shared-memory option.
- The terminal program itself - though as I said I never observed a performance issue with
kitty
.
Anyone tested this on windows and when running inside a container yet ? :)
While it is possible that there is a Windows terminal which supports graphics, if such a terminal is not detected, then image display is disabled as stated above. For example, no banner is displayed when running Maven integration tests (at least in my test program).
There should of course be a manual override switch though.
So I love this, but I have a suggestion. It'd be cute to auto-convert the png to ascii art for the cases where this doesn't work. That saves people having to provide a fallback, and ascii art is just awesome anyway.
That's a cool idea. Are you thinking e.g. interpolating to RGB unicode half-blocks, or actually interpolating to ascii like e.g. https://www.asciiart.eu/image-to-ascii to get something like:
+++++++++++++++
++ -- + ++ @@@@@@@@ @@ @@ @@@ @@@@@@@ @@ @@ @@ @@ @@@@@@@
++ +#@%* ++ @@ @@ @@ @@ @@@@@ @@ @@@ @@ @@@ @@ @@ @@
++ ++@@@@@---++ @@ @@ @@ @@ @@@ @@@ @@@@@@@ @@@@@ @@ @@ @@@@@
++ *@@@# ++ @@ @@ @@ @@ @@@@@@@ @@ @@ @@ @@@ @@ @@ @@
++ --+++ ++ @@@ @@@ @@@ @@@ @@ @@ @@ @@ @@ @@ @@@ @@@ @ @@
++ +++ ++ @@@@@ @@@@@ @@ @@ @@ @@ @@ @@ @@@@@ @@@@@@
+++++++++++++++ @@@
?
In terms of startup time, according to my highly unscientific measurements, my simple getting-started example starts in about ~320ms with the banner and ~310ms without it. So, there probably is some kind of impact but I don't think that the banner is likely "it". Note that the banner is "loaded" via the recorder even if it isn't displayed. I wouldn't expect this to have much overhead though.
That's a cool idea. Are you thinking e.g. interpolating to RGB unicode half-blocks, or actually interpolating to ascii like e.g. https://www.asciiart.eu/image-to-ascii to get something like:
I hadn't really got that far. I was assuming there was a library we could use, although once you add the requirement that it's a Java library, the selection is limited. And, ideally, it would use terminal colours to replicate the colours in the image, and use a wide range of characters to achieve different segment intensities and shapes. Or you could use emojis to get colours. And to do all that, it might be you'll have to take a longer break from the difficult work in order to write a best-of-breed Java ascii art converter. :)
So for some reason I spent some time tinkering with an alternative text-based banner.
I started with this analysis:
I wrote a crappy image interpolator which gave me this text (ignore github's bad formatting):
▟▀▀▀▄ ▐▌ ▐ █▖ █▀▀▚▖ ▐▌ ▗▞▘ █ ▌ ▗▛▀▀▘
▟▘ ▝▌ ▐▌ ▐ ▟ ▙ █ ▐▌ ▐▌▄▀ █ ▝▌ ▐▌
█ ▛ ▐▌ ▐ ▗▙▄▟▌ █▀▜▛ ▐▛▀▖ █ ▝▌ ▀▚▖
▝▙ ▟▘ ▝▙ █ ▛ ▜▖ █ ▜▖ ▐▌ ▝▙ ▜▖ ▟▘ ▗▛
▀▀█ ▀▀▀ ▝▘ ▘ ▀ ▀ ▝▘ ▝▘ ▀▀▀▘ ▝▀▀▀
I cleaned it up manually to get this:
I'm not sure where I'm going with this. It might be a bit plain-looking to be a good replacement the default banner. Maybe it can be spiced up somehow.
Do we have a target width for this ascii banner? I've converted the Kroxylicious logo to ascii and it was important to have the optimum target width since you can't scale them.
I just determined the width as a function of the original image aspect ratio, based on 5 rows and a font aspect ratio of 3:5 (which appears to be more or less standard for most monospace fonts). Since we generally cannot know the correct maximum banner width, it might be a good idea to send the proper escape code to prevent line wrap for those lines. That way if it overflows, it'll get chopped instead of causing a mess on the screen. I could add that...
Just keep in mind that the current banner is ugly because Windows was really hard to get right.
Having a logo be ascii art friendly was NEVER discussed at design school. LOL! Honestly, trying to do the full logo is very problematic as it forces the counter forms of the logo mark to fill in horribly.
I've tweaked the logomark (icon) and rendered it at 100 characters (and adjusted the density sliders to get the best result).
Yeah, it's tricky when it's scaled down. I'd be hesitant to go much higher than five rows of text let alone 100 😉. Even just doing the letters, it doesn't look amazing at that scale. Definite retro PC vibes. :)
Pushed. Now we have separate config for graphical banners, plus a separate switch. Also some knobs for adjusting the size, and a default graphical banner.
I've also updated the text banner, but as @gsmet says it probably will look bad on windows. I'm going to boot up my windows vm and have a look.
Update: it appears I have vaporized my Windows VM. So, it's on the back burner again.
🎊 PR Preview c02cafbd5de6f3f9ef252ae58ad13f25e4f8a14b has been successfully built and deployed to https://quarkus-pr-main-40226-preview.surge.sh/version/main/guides/
- Images of blog posts older than 3 months are not available.
- Newsletters older than 3 months are not available.

Oh, to enable at run time use -Dquarkus.banner.image.enabled=true
. Maybe we should make it the default? (It'll still be disabled if the console does not appear to support graphics though...)
The above text banner does indeed look bad on Windows (missing Unicode characters).
This one looks OK in cmd.exe
, though it's even lower resolution:
▄█▀▀█▄ █ █ ▐█▌ █▀▀▀▄ █ ▄█ █ █ ▄▀▀▀▄
█ █ █ █ ▐▌ ▐▌ █ █ █▄█▀ █ █ █
█ █ █ █ █▄▄▄█ █▀█▀ ██▄ █ █ ▀▀▀▄
█▄ ▄█ ▐▌ ▐▌ ▐▌ ▐▌ █ █ █ ▀█▄ ▐▌ ▐▌ ▄ █
▀▀▀█▄ ▀▀▀▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀▀▀ ▀▀▀
Please please dont enable this by default.
It's fine to have as an option - but consistency is important and having to deal with the amount of different fonts and behaviors across all crazy combos of windows, osx, Linux and containers in and outside proper set of OS and just rendering inside let's say GitHub actions is going to not make this worth having it by default.
Don't worry @maxandersen, as I said before, it won't attempt to display the banner unless there is a high confidence that it will work, even if it is explicitly enabled.
@insectengine did you have any thoughts about a transparent-background, PNG-format version of the banner that looks good on both light and dark backgrounds?
Alternatively we could have separate config for light-mode and dark-mode banner PNG images.
@dmlloyd - I take it we can only have one .PNG that will be accessible (we can't pull a version for light and a version for dark)? If that's the case, then we'd be better off picking one direction and doing an non-transparent version with either a filled light or dark background.
Additionally, we need a minimum amount of space around the logo (as per our branding guidelines). https://quarkus.io/brand/
I'm attaching two versions of the logo with in built in spacing and white or black backgrounds.