Flags (not the int type) from kdelibs4support
Open, Needs TriagePublic

Description

kdelibs4support installs a tonne of icons of flags. Flags as in the icon of different countries.

It's an easy thing to miss as our Plasma code is just loading from /usr/share/kf5/locale/countries
without any API used.

Despite the kf5 name, that's still from kdelibs4support providing them. The kf5 prefix is just for co-install-ability.

We use this from Plasma for:

  • the formats KCM
  • the locale KCM
  • the keyboard layout indicators

Apparently a copy of these icons exists in marble.

Options are:

  • Put them all in breeze (country codes are part of the default icon spec)

https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html (table 9)

  • Use emoji flags
  • Make it a plasma problem?

Related Objects

bam added a subscriber: bam.Oct 5 2020, 12:43 PM

option 2 has the advantage that we do not need to maintain the flags (country changes flags or new country appearing). However we do not have control about the appearance of the flag which we would have with option 1.

ndavis added a subscriber: ndavis.Oct 5 2020, 1:55 PM

I prefer option 2

I'd say 1+2:

  • move them all to breeze
  • look into emoji flags, if it's viable, use it, and keep the ones in breeze as fallback (no idea how simple/complicated that could turn out to be)
  • otherwise just use them from breeze.
ndavis added a comment.Oct 5 2020, 2:12 PM

I don't think non-Breeze icons should go into breeze-icons. I especially don't want PNGs in breeze-icons unless they really need to be there.

I don't think non-Breeze icons should go into breeze-icons. I especially don't want PNGs in breeze-icons unless they really need to be there.

Ah, good point, I didn't think of that. Then s/breeze/whatever repo contains all those KCMS/ :)

If we want to go the icon theme route we could create an icontheme for the flags and breeze could inherit from that. So we could still do QIcon::fromTheme("flag-DE")

vkrause added a subscriber: vkrause.Oct 5 2020, 2:18 PM

For option (2) a little helper function like https://invent.kde.org/pim/itinerary/-/blob/master/src/app/localizer.cpp#L41 somewhere in a low-tier framework might be useful.

ndavis added a comment.Oct 5 2020, 2:18 PM

If we want to go the icon theme route we could create an icontheme for the flags and breeze could inherit from that. So we could still do QIcon::fromTheme("flag-DE")

yes, that should be fine if we still want to have an icon theme with flags.

bam added a comment.Oct 5 2020, 3:01 PM

Thanks for input everyone.
About option 2, if someone knows emoji font resemble these: https://lxr.kde.org/source/frameworks/kdelibs4support/src/l10n/ (the flags are inside 2-letter dirs, installing to kf5/locale/countries/%1/flag.png), please let us know. I think non-waving version is preferable.

ndavis added a comment.Oct 7 2020, 3:09 PM
In T13722#241999, @bam wrote:

Thanks for input everyone.
About option 2, if someone knows emoji font resemble these: https://lxr.kde.org/source/frameworks/kdelibs4support/src/l10n/ (the flags are inside 2-letter dirs, installing to kf5/locale/countries/%1/flag.png), please let us know. I think non-waving version is preferable.

Not sure we really have any control over the style of emoji since distros can set that, but Twemoji is a pretty comprehensive and popular FOSS emoji font with non-waving flags: https://emojipedia.org/twitter/

bam added a comment.Oct 7 2020, 4:20 PM

...
non-waving flags: https://emojipedia.org/twitter/

Thanks, looks OK! They have round corners but maybe it's a minor issue.
The main point I'm targeting here is to make them look good with 2-letter country code on top.

bam added a subscriber: mart.EditedJan 4 2021, 3:43 PM

Advantage of "real" icon is that it supports overlay text on top (IconItem), and can be highlighted in a standard way (with Active mode).
So it's still a reasonable alternative over emoji I think.
@mart

ndavis added a comment.EditedJan 5 2021, 3:55 PM

@bam I suppose I could take the Twemoji flags, sharpen the corners and then put them in breeze-icons. It'll probably take a long time though since there are a lot of flags and I'll have to recreate any bits of the flag that were cut off by having the corners rounded.

bam added a comment.Jan 5 2021, 5:35 PM

Thanks Noah. Yes that support burden frightens me also (not sure how often they are updating, though).
What do you think about Openmoji? Sharp corners but thick black outline. Still might look good, IMO.
And about the corners, maybe round corners are not that bad?
Or just create several flag themes, one for each emoji vendor?
Too many questions, I know.

Also I invited people from Marble devlist to join the discussion (my message is on moderation currently):
https://mail.kde.org/mailman/listinfo/marble-devel

bam added a comment.Jan 5 2021, 7:14 PM

Marble has full-fledged flags from Widipedia, they are not suit well our needs: https://invent.kde.org/education/marble/-/tree/master/data/flags
The only abstracted variant I faced is OpenMoji, for comparison: https://emojipedia.org/flag-afghanistan/

bam added a comment.Jan 8 2021, 5:39 PM
In T13722#247618, @bam wrote:

What do you think about Openmoji? Sharp corners but thick black outline. Still might look good, IMO.

That outline is just a separate SVG element (<g id="line">), should be easy to remove automatically.

ndavis added a comment.Jan 9 2021, 3:33 PM

I'm not a fan of the style of OpenMoji, even if the black outlines were removed. Also, looking at the Afghanistan flag you linked, the OpenMoji variant leaves out quite a bit of detail. Some of the details even seem wrong.

Twemoji:

https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/240/twitter/259/flag-afghanistan_1f1e6-1f1eb.png

OpenMoji:

https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/openmoji/272/flag-afghanistan_1f1e6-1f1eb.png

bam added a comment.Jan 10 2021, 3:28 PM

It seems to me Twemoji still has much more details for that flag.
Anyway, could we have more than one flag vendors available?
Ideally, they should be just auto-generated from that vendors, shall the modifications needed at all.

It seems to me Twemoji still has much more details for that flag.

Yes, I was saying that Twemoji was more detailed and correct than OpenMoji.

Anyway, could we have more than one flag vendors available?
Ideally, they should be just auto-generated from that vendors, shall the modifications needed at all.

You mean get flags from more than one pack of emojis? I don't think that's a good idea. I don't think there are enough similar sets of flags that we can mix and match without things looking wrong. Unless we want to maintain the flags ourselves, our best bet is to just use Twemoji.

bam added a comment.Jan 10 2021, 5:19 PM

Yes, I was saying that Twemoji was more detailed and correct than OpenMoji.

The idea was having more details is not necessary good for this particular case. I thought having flags somewhat abstracted is what we need here, and only OpenMoji suits that idea what I can see.
Maybe I'm wrong, need to see it in actual scale in comparison.

You mean get flags from more than one pack of emojis? I don't think that's a good idea. I don't think there are enough similar sets of flags that we can mix and match without things looking wrong. Unless we want to maintain the flags ourselves, our best bet is to just use Twemoji.

I just hoped user could choose one flags icon pack or another without mixing. I'm not sure if Plasma theme's engine allows this.
I'm not in favor of maintaining flags also, that is why I suggested automated handling in scripts or whatever.
Could we convert corners shape for Twemoji automatically?

ndavis added a comment.EditedJan 11 2021, 6:57 AM

Maybe we're not communicating with each other well? My impression is that any emoji set we pick will become the default system-wide emoji set. If that is the case, then we need to be prepared for emojis to show up at any size. I think Twemoji's style has a good enough compromise between accuracy and legibility at small sizes.

Could we convert corners shape for Twemoji automatically?

Maybe some of the flags could be automated, but only the ones that have only one solid color in the area of each corner could be fully automated. It wouldn't be easy either. We'd have to figure out which parts of the SVG make up the corners (flags can have different shapes and aspect ratios), check if a given SVG element fills up the area of one or more corners (probably requires some Bezier curve math, you can't just use the element's bounding rect) and then combine it with a rectangular path that has the same position, area and color as the corner.

ndavis added a comment.EditedJan 11 2021, 7:03 AM

I just hoped user could choose one flags icon pack or another without mixing. I'm not sure if Plasma theme's engine allows this.

If we add a way to customize the system wide emoji set, we could have that. If we're just putting the flags into breeze-icons, then users won't have any choice but to use breeze-icons since no other icon theme would have flags.

bam added a comment.Jan 13 2021, 3:12 PM

I think it would be cool if we just started with anything.
Just need to watch new icons looks not worse in small scale than kdelibs4suppors's ones.

rahn added a subscriber: rahn.Feb 1 2021, 7:17 PM

I don't have much to add from the Marble side. But I'm curious to see anything new you come up with.

IlyaBizyaev added a subscriber: IlyaBizyaev.

I believe that it is necessary to replace all the flag icons in the svg, for better display at different panel heights. Now png icons look disgusting and blurry when scaled.

ZaWertun added a subscriber: ZaWertun.EditedMay 13 2021, 2:29 PM

Black outline in OpenMoji can be simply hidden by this CSS rule:

<style>
  #line { display: none; }
</style>

Or removed with use of any XML library - by removing tag <g id="line">.

And still I think that OpenMoji flag icons still better than Twemoji.
Those tiny elements on flags still can't be seen on small icons.
Example (generated by Inkscape):

Simple Ruby script to remove black outlines in OpenMoji flags:

require 'rexml/xpath'
require 'rexml/document'

include REXML

doc = Document.new File.open(ARGV[0])
XPath.first(doc, '//*[@id="line"]').remove
File.open(ARGV[0], 'w') {|res| doc.write(res) }


On the left is an icon from https://openmoji.org, on the right is a standard icon. The difference is obvious when the panel size is large.

If it's possible to remove the black outline, then I guess we can use OpenMoji for flags.

We can remove black border from all icons.

bam added a comment.May 13 2021, 7:02 PM

@driglu4it we also have problem with blurring SVG icons on small sizes, could you also provide the screenshots?

reading over convo: I think we should use Twemoji, they are clearly more accurate
also imo round corners look on flags look really nice

In T13722#255639, @bam wrote:

@driglu4it we also have problem with blurring SVG icons on small sizes, could you also provide the screenshots?

Panel height is 36

In T13722#255639, @bam wrote:

@driglu4it we also have problem with blurring SVG icons on small sizes, could you also provide the screenshots?

Panel height is 36

Yeah that's pretty blurry, though not a problem specific to OpenMoji. Twemoji probably has the same problem. That's just what happens when you don't make images for the exact size you will be using them at. Another example: 🇺🇸

bam added a comment.May 14 2021, 9:35 AM

That's just what happens when you don't make images for the exact size you will be using them at

So what should be the solution? I thought strong point of SVG is it doesn't tied to any particular size.

In T13722#255696, @bam wrote:

So what should be the solution?

The solution to the blurriness problem would be to make pixel aligned flags for every icon size we might use. I don't really want to do that though because it would take a long time to do and better emoji support is something we need anyway.

I thought strong point of SVG is it doesn't tied to any particular size.

SVG icons still have to deal with the physical limitations of pixels on a screen. You can scale up SVG icons pretty well, which is something you can't do with raster graphics, but you often can't scale things down well. If you make a 64x64 icon and scale it down to 16x16, it's probably going to look blurry because there just aren't enough physical pixels to faithfully represent the icon.

bam added a comment.May 14 2021, 2:16 PM

The solution to the blurriness problem would be to make pixel aligned flags for every icon size we might use.

Do you mean in raster?

You can scale up SVG icons pretty well, which is something you can't do with raster graphics, but you often can't scale things down well.

Still, the problems seem begin even before we squash image small enough so that lack of pixels might be a problem.
It can be seen even in FF, e.g here flag in bottom row is already blurry while it still big enough:
https://openmoji.org/library/#group=flags&emoji=1F1FA-1F1F8

I have a theory what's going on.

  • the initial size SVG was made for is stored somewhere
  • if we upscale the icon above that size, all is perfect because the render is calculated directly from vector data
  • if we downscale below that size, what happens is:
    • first, base raster image for initial size is rendered to buffer
    • then, the buffer downscales further as raster image, producing blurring glitches we see in the examples above

Can it be near to truth?

In T13722#255709, @bam wrote:

Do you mean in raster?

No, SVGs

I have a theory what's going on.

  • the initial size SVG was made for is stored somewhere

Correct. It's stored in the beginning <svg> tag as an attribute. However, it is not necessarily the reason why the blurriness happens.

  • if we upscale the icon above that size, all is perfect because the render is calculated directly from vector data
  • if we downscale below that size, what happens is:
    • first, base raster image for initial size is rendered to buffer
    • then, the buffer downscales further as raster image, producing blurring glitches we see in the examples above

      Can it be near to truth?

No. It's just because of how the math matches up to physical pixels on the screen.


I'm going to try to explain some basic facts about SVG.

With SVG, there are 2 types of pixels.

  1. Pixels as a physical unit on a screen.
  2. Pixels as a logical grid unit of arbitrary size, but usually scaled to fit the physical pixels on the screen. These are usually abbreviated with px.

When I say a line in an SVG is 1px thick or that an SVG is 16x16, I mean the 2nd type of pixel. I call them pixels because everyone including the SVG spec calls them pixels even though they are not physical pixels.

The physical pixels are a limitation that we can't work around. If you try to render a black 1px thick line between physical pixels, you will instead get a gray 2px thick line because the black 1px thick line is being averaged between the 2 pixels. This is what causes the blurriness.

At best, we can try to do fancy things like subpixel antialiasing, where colors on the edges of shapes are altered so that the red/green/blue subpixels aren't evenly lit, raising the effective horizontal resolution by 3x. However, this is complicated and mostly irrelevant for SVGs since I'm not aware of a way to render SVGs with subpixel antialiasing using the Qt SVG renderer.


Here is the inside of a basic 16x16 svg. It has a black rectangle filling the entire area of the svg and a white rectangle with 1px of margin on each side, causing the black rectangle to look like an outline. px is the default unit type. We can choose to use millimeters, inches, px, ems or whatever, but we still have to deal with the physical limitations of the computer screen.

<svg version="1.1" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
    <rect x="0" y="0" width="16" height="16" fill="#000000"/>
    <rect x="1" y="1" width="14" height="14" fill="#ffffff"/>
</svg>

It looks like this at its default size (16x16):

It looks like this at 2x its default size (32x32):

Nice and crisp because the math scales up to 32x32 very well.

It looks like this at 0.5x its default size (8x8):

If you look closer, you can see what I mean when I say that things are being averaged between pixels. The 8x8 version, but zoomed in on the rendered result 6x:

Logically, the margins around the white square should be 0.5 pixels for each side, right? Instead, we get the same 1 pixel thick margins, but with averaged colors. It's simply impossible to draw it properly on physical pixels.

ngraham added a subscriber: ngraham.EditedMay 14 2021, 4:20 PM

TL;DR version: SVG lets you scale up a small image without losing sharpness, but not when you scale down a large image. Resolution and visual quality are always limited by the size of the physical pixels on your screen.

bam added a comment.May 14 2021, 10:35 PM

Thanks for the in-depth description and clarification.

The solution to the blurriness problem would be to make pixel aligned flags for every icon size we might use.

I asked upstream to see what reaction would be for providing smaller variants of the icons:
https://github.com/hfg-gmuend/openmoji/issues/317

Try also setting mipmap to true: https://doc.qt.io/qt-5/qml-qtquick-image.html#mipmap-prop.
Maybe it will give better results (disabled by default).

Try also setting mipmap to true: https://doc.qt.io/qt-5/qml-qtquick-image.html#mipmap-prop.
Maybe it will give better results (disabled by default).

Actually, a Text/Label element would be better for showing emojis at small sizes because it supports subpixel antialiasing.

Try also setting mipmap to true: https://doc.qt.io/qt-5/qml-qtquick-image.html#mipmap-prop.
Maybe it will give better results (disabled by default).

yes, it got better, but still bad ...

bam added a comment.May 17 2021, 1:06 PM

Relevant setting, true by default:
https://doc.qt.io/qt-5/qml-qtquick-image.html#smooth-prop
I wonder if it makes any impact when scaling up in several sizes, 2x or more..

bam added a comment.May 17 2021, 1:12 PM

Actually, a Text/Label element would be better for showing emojis at small sizes because it supports subpixel antialiasing.

Even so, seems old hand-made PNGs drawn on pixel-by-pixel basis give the best result at smallest size, so I doubt we need to smash it to something else. Rather than adding on top, maybe.

From the last KF6 meeting, it looks like:

  • the usage of emoji is being implemented as part of the locale work (see T12429 )
  • the last part of the discussion is about implementing real artwork, but there is nothing which blocks KF6, so I'm going to move this to backlog.

Feel free to move it back to "needs input" (or any other more appropriate state) if I've missed something.

ltoscano moved this task from Needs Input to Backlog on the KF6 board.Jun 12 2021, 1:41 PM
ognarb added a subscriber: ognarb.Jun 13 2021, 6:51 PM

Small warning with emojis, in QML apps there are some difficulties to render them: https://bugreports.qt.io/browse/QTBUG-85744 if you don't explicitly set the font to 'emoji'

Small warning with emojis, in QML apps there are some difficulties to render them: https://bugreports.qt.io/browse/QTBUG-85744 if you don't explicitly set the font to 'emoji'

Interesting, Itinerary and KTrip are using emoji flags in QML labels since quite some time without special font handling, and that seems to work just fine on Linux and Android at least.

Small warning with emojis, in QML apps there are some difficulties to render them: https://bugreports.qt.io/browse/QTBUG-85744 if you don't explicitly set the font to 'emoji'

Interesting, Itinerary and KTrip are using emoji flags in QML labels since quite some time without special font handling, and that seems to work just fine on Linux and Android at least.

It really depends on the distribution, Neon has a font hack to make it work but on openSUSE, Fedora, Arch and Alpine this breaks. Currently, I'm asking users with problems with emojis to add: https://invent.kde.org/network/neochat/-/blob/master/cmake/Flatpak/99-noto-mono-color-emoji.conf in their fontconfig. If I remember correctly I didn't saw such problems on Android, so maybe the font stack there is a bit different.

sitter added a subscriber: sitter.EditedJan 11 2023, 11:56 AM

*cough* I'll just leave a prototype of a qiconengine based on emojis here.

// SPDX-License-Identifier: LGPL-2.1-or-later
// SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
class FlagIconEngine : public QIconEngine
{
public:
    explicit FlagIconEngine(const QString &country)
        : m_country(country.toUpper())
    {
    }

    QIconEngine *clone() const override
    {
        return new FlagIconEngine(m_country);
    }

    QString key() const override
    {
        return m_country;
    }

    void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override
    {
        static constexpr auto surrogatePairCodePoint = 0xD83C;
        static constexpr auto flagCodePointStart = 0xDDE6; // https://en.wikipedia.org/wiki/Regional_indicator_symbol
        static constexpr auto offsetCodePointA = QChar('A').unicode(); // offset from 0, the flag code points have the same offsets
        static constexpr auto basePoint = flagCodePointStart - offsetCodePointA;

        QString emoji;
        for (const auto &c : m_country) {
            emoji.append(surrogatePairCodePoint);
            emoji.append(QChar(basePoint + c.toUpper().unicode()));
        }

        Q_ASSERT(!emoji.isEmpty());

        QFont font("Noto Color Emoji; emoji");
        font.setPixelSize(rect.height());
        QFontMetricsF metrics(font);
        QRectF dest(metrics.boundingRect(emoji));
        dest.moveCenter(rect.center());
        // TODO handle width>height

        painter->setFont(font);
        painter->drawText(dest, emoji, QTextOption(Qt::AlignCenter));
    }

private:
    const QString m_country;
};
nicolasfella moved this task from Backlog to In Progress on the KF6 board.Feb 23 2023, 9:19 PM

plasma-workspace/kcms/region_language still uses the old flags lookup

sitter added a comment.Jul 8 2023, 3:31 PM

https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/3052

threw this together in a hurry. at a glance the performance doesn't look good with sync icon resolution