13rac1 / twemoji-color-font

Twitter Unicode emoji color OpenType-SVG font for Linux/MacOS/Windows
Other
1.71k stars 75 forks source link

Better Fallback #74

Open adyeths opened 4 years ago

adyeths commented 4 years ago

I was thinking that the automatically generated black and white fallback should be better than it currently is, so I started playing around with trying to come up with a better way to automatically create them. I think I can have come up with something that works.

Here are examples of the commands that I came up with while experimenting:

rsvg-convert -a -b white -w 1000 -h 1000 -o generated.png input.svg
convert generated.png -scale 1000x1000 -gravity center -extent 102.4% +antialias -colorspace Gray -blur 5 -canny 0x0+99%+1% -morphology Dilate Diamond:3 -negate generated.pgm
potrace --backend svg --flat -o new.svg generated.pgm

The convert command does all the magic. I'm sure it could be tweaked to produce even better results, but this produces quite nice results.

13rac1 commented 4 years ago

Interesting! Thanks for working on this idea. I've always wondered if/when someone would figure a way to make these better. I'll try this out. We need some comparisons posted to this issue.

adyeths commented 4 years ago

Here are links three examples that I generated using my method...

example 1

example 2

example 3

ahyangyi commented 4 years ago

Wow, this looks awesome. I was about to create a similar (but inferior) issue before I found this...

ahyangyi commented 4 years ago

My suggestion: do not set the background to pure white. Set it to something rarely used. I personally use #ff00ff which is the classical "impossible" color.

One of the emojis affected by different background colors is 1f1e7-1f1fe, the Belarusian flag.

trace with white background: before-2

trace with magenta background: after

I added -background "#FF00FF" to the convert command line, and I did not set a background color to the inkscape command.

ahyangyi commented 4 years ago

I guess I am probably boar'd today! I made another attempt.

I personally prefer the monochrome font to use thicker lines and fill in all “dark” regions of the emoji, since that blends better with the typical sans-serif system UI fonts.

build/svg-bw/%.svg: build/staging/%.svg | build/svg-bw
    inkscape -w 1000 -h 1000 -z --export-file=$(TMP)/$(*F).png $<
    convert $(TMP)/$(*F).png -level 0%,115% -background "#FFFFFF" -gravity center -extent 1050x1050 +antialias -colorspace Gray -blur 3 $(TMP)/$(*F)_gray.png
    convert $(TMP)/$(*F)_gray.png -threshold 10% -morphology EdgeIn:12 Disk $(TMP)/$(*F)_threshold_1.pgm
    convert $(TMP)/$(*F)_gray.png -threshold 20% -morphology EdgeIn:12 Disk $(TMP)/$(*F)_threshold_2.pgm
    convert $(TMP)/$(*F)_gray.png -threshold 30% $(TMP)/$(*F)_threshold_3.pgm
    convert $(TMP)/$(*F)_gray.png -threshold 40% -morphology EdgeOut:12 Disk -negate $(TMP)/$(*F)_threshold_4.pgm
    convert $(TMP)/$(*F)_gray.png -threshold 51% -morphology EdgeOut:12 Disk -negate $(TMP)/$(*F)_threshold_5.pgm
    convert $(TMP)/$(*F)_gray.png -threshold 60% -morphology EdgeOut:12 Disk -negate $(TMP)/$(*F)_threshold_6.pgm
    convert $(TMP)/$(*F)_gray.png -threshold 70% -morphology EdgeOut:12 Disk -negate $(TMP)/$(*F)_threshold_7.pgm
    convert $(TMP)/$(*F)_gray.png -threshold 80% -morphology EdgeOut:12 Disk -negate $(TMP)/$(*F)_threshold_8.pgm
    convert $(TMP)/$(*F)_gray.png -threshold 90% -morphology EdgeOut:12 Disk -negate $(TMP)/$(*F)_threshold_9.pgm
    convert $(TMP)/$(*F)_threshold_3.pgm \
        $(TMP)/$(*F)_threshold_1.pgm -compose Screen -composite \
        $(TMP)/$(*F)_threshold_2.pgm -compose Screen -composite \
        $(TMP)/$(*F)_threshold_4.pgm -compose Multiply -composite \
        $(TMP)/$(*F)_threshold_5.pgm -compose Multiply -composite \
        $(TMP)/$(*F)_threshold_6.pgm -compose Multiply -composite \
        $(TMP)/$(*F)_threshold_7.pgm -compose Multiply -composite \
        $(TMP)/$(*F)_threshold_8.pgm -compose Multiply -composite \
        $(TMP)/$(*F)_threshold_9.pgm -compose Multiply -composite \
        $(TMP)/$(*F).pgm
    rm $(TMP)/$(*F).png $(TMP)/$(*F)_gray.png
    potrace --flat -s --height 2048pt --width 2048pt -o $@ $(TMP)/$(*F).pgm
    rm $(TMP)/$(*F).pgm \
        $(TMP)/$(*F)_threshold_1.pgm \
        $(TMP)/$(*F)_threshold_2.pgm \
        $(TMP)/$(*F)_threshold_3.pgm \
        $(TMP)/$(*F)_threshold_4.pgm \
        $(TMP)/$(*F)_threshold_5.pgm \
        $(TMP)/$(*F)_threshold_6.pgm \
        $(TMP)/$(*F)_threshold_7.pgm \
        $(TMP)/$(*F)_threshold_8.pgm \
        $(TMP)/$(*F)_threshold_9.pgm

So here are my experiment results.

Benchmark: 1f417, the boar

boar

Old script

boar

@adyeths's script

boar

My new script

boar

For the Belarus flag, my new script is not perfect but the result is recognizable:

boar

However, my script is agonizingly slow, so maybe some optimization needs to be done...

EDIT, ouch, it seems the current list of thresholds is not enough...

adyeths commented 4 years ago

I had experimented with trying to preserve some of the fill characteristics but I was never quite happy with the results. It's not bad but I believe it could be improved. Here is the convert command that I used for this in case you want to experiment with it.

convert input.png \
        -gravity center \
        -background \#ff00ff \
        -extent 102.4% \
        -flatten \
        -scale 1536x1536 \
        \( +clone \
           -canny 0x1+.01%+1% \
           -morphology Dilate:10 Diamond \
           -negate \
        \) \
        -fill white \
        +fuzz \
        -opaque '#FF00FF' \
        -opaque '#A0041E' \
        -opaque '#BE1931' \
        -opaque '#EB2027' \
        -opaque '#FF000E' \
        -opaque '#FF5000' \
        -opaque '#DD2E44' \
        -opaque '#5C913B' \
        -opaque '#138F3E' \
        -opaque '#226798' \
        -opaque '#226699' \
        -opaque '#3558A0' \
        -opaque '#004A77' \
        -opaque '#744EAA' \
        -opaque '#880082' \
        -opaque '#66757F' \
        -opaque '#7C533E' \
        -opaque '#7C543E' \
        -opaque '#DA2F47' \
        -colorspace Gray \
        -threshold 45% \
        -compose Darken \
        -composite \
        output.pgm
ghost commented 4 years ago

Sorry to bump this, but could a branch or fork be made with the dark fill emoji and the output font? I'm entirely unable to read the current B&W emoji because of the tiny details & small stroke.

Compare: New - & old - .

13rac1 commented 4 years ago

@nedevel I'm building this right now with @ahyangyi script. It is so slow :turtle: Interested to see what happens though :man_shrugging:

13rac1 commented 4 years ago

@ahyangyi Wow. It is so so so slow. 20mins for the regular build vs hours and hours. I'm timing this. It wouldn't be bad if the files were generated then committed.

13rac1 commented 4 years ago

:laughing: This is quite a bit longer than the regular build:

real    637m51.631s
user    2319m55.108s
sys 17m29.041s

20mins vs 10.5hrs

13rac1 commented 4 years ago

Added to the current release. I don't intend to make this the default though, because of the 10.5hr build. Try it out. If someone can determine an even better process which doesn't take as long I'll be happy to implement it.

13rac1 commented 3 years ago

Rebased for 13.1.0 on https://github.com/eosrei/twemoji-color-font/tree/thickfallback I don't to build this myself due to the 10+ hr build time.

Humming-Owl commented 2 years ago

I have been messing around a little and got these results:

1f1f9-1f1eb

1f0cf

1f387

1f9d1-200d-1f692

The contour lines are still very thin but if I add more thickness to them, images like the flags get very bad.

Humming-Owl commented 2 years ago

I improved a little bit more how to process the SVG images and ended with this script (Bash).

You need the Image Magick binary from the main page in the same location as the script for it to work. Also a folder called "input" with the SVG images.

https://github.com/Humming-Owl/scripts/blob/main/svgtobw.sh

It will create a "final" folder with the resulting images.

adyeths commented 2 years ago

It occurred to me that rasterizing, converting to black and white, and then tracing the images was completely unnecessary. So here's a significantly faster way to make black and white fallback svg's using only sed.

# from inside directory containing svg... will place black and white svg's in output directory...
for i in *.svg ; do 
    sed -r -e 's/ fill="(#[A-Z0-9]{3,6}|[a-z]+)"/ fill="white" stroke="black" stroke-width=".5" /gi;' < $i > output/$i
done

1f0cf 1f3a2 1f5fb

adyeths commented 2 years ago

One more update from me... I made a simple python script to convert the svg's to black and white, with an attempt at adding fills where they seemed appropriate. source is here -> https://gist.github.com/adyeths/ec20a69e35f2817110aeb13df7ed8b43

1f0cf 1f1f5-1f1f2 1f3c1 1f417