quarkus icon indicating copy to clipboard operation
quarkus copied to clipboard

Support graphical banners

Open dmlloyd opened this issue 10 months ago • 15 comments

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!

image

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.

dmlloyd avatar Apr 23 '24 17:04 dmlloyd

Glamorous :)

aloubyansky avatar Apr 23 '24 19:04 aloubyansky

Cool :)

Sanne avatar Apr 24 '24 06:04 Sanne

It looks really cool.

This is the coolest thing I've seen in a while!

geoand avatar Apr 24 '24 11:04 geoand

Holy crap, that's amazing!

Screenshot 2024-04-25 at 17 11 39

gastaldi avatar Apr 25 '24 19:04 gastaldi

@dmlloyd I've tested locally and it looks great. What's missing to make this PR Ready for Review?

gastaldi avatar Apr 25 '24 20:04 gastaldi

Interesting that it doesn't work with quarkus dev

gastaldi avatar Apr 25 '24 20:04 gastaldi

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 the ImageIO 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 from xxxx.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...)

dmlloyd avatar Apr 25 '24 20:04 dmlloyd

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 ? :)

maxandersen avatar Apr 26 '24 06:04 maxandersen

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.

holly-cummins avatar Apr 26 '24 10:04 holly-cummins

That will be a part of boot time that users may use for comparisons though.

aloubyansky avatar Apr 26 '24 12:04 aloubyansky

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.

holly-cummins avatar Apr 26 '24 12:04 holly-cummins

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.

dmlloyd avatar Apr 26 '24 12:04 dmlloyd

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:

+++++++++++++++                                                                                     
++   --  +   ++        @@@@@@@@    @@     @@      @@@      @@@@@@@    @@   @@    @@     @@   @@@@@@@
++   +#@%*   ++       @@      @@   @@     @@     @@@@@     @@   @@@   @@ @@@     @@     @@   @@     
++ ++@@@@@---++      @@       @@   @@     @@    @@@ @@@    @@@@@@@    @@@@@      @@     @@    @@@@@ 
++   *@@@#   ++       @@      @@   @@     @@    @@@@@@@    @@  @@     @@ @@@     @@     @@        @@
++   --+++   ++       @@@   @@@    @@@   @@@   @@     @@   @@   @@    @@   @@    @@@   @@@   @    @@
++    +++    ++         @@@@@        @@@@@     @@      @@  @@    @@   @@    @@     @@@@@     @@@@@@ 
+++++++++++++++             @@@                                                                     

?

dmlloyd avatar Apr 26 '24 12:04 dmlloyd

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.

dmlloyd avatar Apr 26 '24 13:04 dmlloyd

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. :)

holly-cummins avatar Apr 26 '24 14:04 holly-cummins

So for some reason I spent some time tinkering with an alternative text-based banner.

I started with this analysis:

quarkus-grid

I wrote a crappy image interpolator which gave me this text (ignore github's bad formatting):

 ▟▀▀▀▄   ▐▌   ▐     █▖    █▀▀▚▖  ▐▌ ▗▞▘  █    ▌  ▗▛▀▀▘
▟▘   ▝▌  ▐▌   ▐    ▟ ▙    █  ▐▌  ▐▌▄▀    █   ▝▌  ▐▌   
█     ▛  ▐▌   ▐   ▗▙▄▟▌   █▀▜▛   ▐▛▀▖    █   ▝▌    ▀▚▖
▝▙   ▟▘  ▝▙   █   ▛   ▜▖  █  ▜▖  ▐▌ ▝▙   ▜▖  ▟▘     ▗▛
  ▀▀█      ▀▀▀   ▝▘    ▘  ▀   ▀  ▝▘  ▝▘   ▀▀▀▘   ▝▀▀▀ 

I cleaned it up manually to get this:

image

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.

dmlloyd avatar May 01 '24 15:05 dmlloyd

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.

insectengine avatar May 01 '24 15:05 insectengine

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...

dmlloyd avatar May 01 '24 16:05 dmlloyd

Just keep in mind that the current banner is ugly because Windows was really hard to get right.

gsmet avatar May 01 '24 16:05 gsmet

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).

quarkus_icon_ascii_100

quarkus_icon_ascii_100.txt

insectengine avatar May 01 '24 16:05 insectengine

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. :)

dmlloyd avatar May 01 '24 18:05 dmlloyd

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.

dmlloyd avatar May 01 '24 18:05 dmlloyd

🎊 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.

github-actions[bot] avatar May 01 '24 18:05 github-actions[bot]

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...)

dmlloyd avatar May 01 '24 18:05 dmlloyd

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:

▄█▀▀█▄  █    █    ▐█▌    █▀▀▀▄   █  ▄█  █    █  ▄▀▀▀▄
█    █  █    █   ▐▌ ▐▌   █   █   █▄█▀   █    █  █    
█    █  █    █   █▄▄▄█   █▀█▀    ██▄    █    █   ▀▀▀▄
█▄  ▄█  ▐▌  ▐▌  ▐▌   ▐▌  █  █    █ ▀█▄  ▐▌  ▐▌  ▄   █
 ▀▀▀█▄   ▀▀▀▀   ▀     ▀  ▀   ▀   ▀   ▀   ▀▀▀▀    ▀▀▀ 

Screenshot_2024-05-02_12-56-19 image

dmlloyd avatar May 02 '24 18:05 dmlloyd

Please please dont enable this by default.

maxandersen avatar May 03 '24 06:05 maxandersen

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.

maxandersen avatar May 03 '24 06:05 maxandersen

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.

dmlloyd avatar May 03 '24 11:05 dmlloyd

@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 avatar May 06 '24 18:05 dmlloyd

@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. quarkus_logo_horizontal_default_black quarkus_logo_horizontal_default_white

insectengine avatar May 06 '24 19:05 insectengine