Produce Theme Specific GTK3 and Metacity Thumbnails
actionless opened this issue · 24 comments
From @smurphos on August 26, 2017 9:7
The thumbnails currently produced on exporting a theme are the generic Numix thumbnails - it would be good if they reflected the theme characteristics being exported.
Copied from original issue: themix-project/themix-gui#97
Hi,
I tried creating a SVG version of gtk-3.0/thumbnail.png
:
(zip is here)
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="35" viewBox="0 0 120 35">
<defs>
<linearGradient id="bg"><stop stop-color="#DEDEDE"/></linearGradient>
<linearGradient id="button-bg" x2="0" y2="1">
<stop stop-color="#F0F0F0"/>
<stop stop-color="#F0F0F0" offset="1"/>
</linearGradient>
<linearGradient id="button-fg"><stop stop-color="#555555"/></linearGradient>
<linearGradient id="button-border"><stop stop-color="#9C9C9C"/></linearGradient>
<linearGradient id="checkradio-bg"><stop stop-color="#F9F9F9"/></linearGradient>
<linearGradient id="checkradio-fg"><stop stop-color="#D64937"/></linearGradient>
<linearGradient id="checkradio-border"><stop stop-color="#A8A8A8"/></linearGradient>
<filter id="drop-shadow" color-interpolation-filters="sRGB" x="-0.5" y="-0.5" width="2" height="2">
<feGaussianBlur in="SourceAlpha" stdDeviation="1"/>
<feOffset dx="0" dy="0.5" result="offsetblur"/>
<feFlood flood-color="#000000" flood-opacity="0.12"/>
<feComposite in2="offsetblur" operator="in"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<rect width="120" height="35" fill="url(#bg)"/>
<g transform="translate(2, 2)" id="button">
<rect x="0.5" y="0.5" width="50" height="24" ry="1.5" fill="url(#button-bg)" stroke="url(#button-border)" stroke-width="1" filter="url(#drop-shadow)"/>
<text x="25" y="17" text-anchor="middle" font-family="sans-serif" font-size="9.75pt" fill="url(#button-fg)">Button</text>
</g>
<g transform="translate(60, 6)" id="check">
<rect x="0.5" y="0.5" width="15" height="15" ry="1.5" fill="url(#checkradio-bg)" stroke="url(#checkradio-border)"/>
<path d="M11.681 3.928a1.467 1.467 0 0 0-.987.427L6.653 8.2 5.27 6.65c-.494-.659-1.574-.729-2.146-.142-.572.588-.494 1.692.156 2.186l2.39 2.569c.94.94 1.362.814 2.31-.138 0 0 3.258-3.92 5.169-5.243.423-.4.599-.513.376-1.054-.22-.544-1.27-.92-1.845-.9z" fill="url(#checkradio-fg)"/>
</g>
<g transform="translate(86, 6)" id="radio">
<circle cx="8" cy="8" r="7.5" fill="url(#checkradio-bg)" stroke="url(#checkradio-border)"/>
<circle cx="8" cy="8" r="3" fill="url(#checkradio-fg)"/>
</g>
</svg>
Hopefully, users can create a specific PNG with Inkscape (e.g. inkscape -z -e thumbnail.png thumbnail.svg
) after editing the following values with script:
stop-color
ofid="bg"
forBG
stop-color
ofid="button-bg"
forBTN_BG
(and hopefullyGRADIENT
)stop-color
ofid="button-fg"
forBTN_FG
stop-color
ofid="button-border"
for darkerBTN_BG
(?)stop-color
ofid="checkradio-bg"
forTXT_BG
stop-color
ofid="checkradio-fg"
forSEL_BG
stop-color
ofid="checkradio-border"
for darkerTXT_BG
(?)ry
(value =border-radius
-border-width
/ 2) forROUNDNESS
stroke-width
for when oomox makesborder-width
configurable (?)
Possibly I need to revise this SVG for the border colors. (It will be a bit complicated to handle ry
then.)
Or can we handle the colors without revision? 🤔 What do you think?
that's really nice, thanks a lot!
tonight i'll integrate that to change_color script
using semi-transparent FG for checkbox will be accurate: https://github.com/actionless/oomox-gtk-theme/blob/master/src/assets/checkbox-checked.svg?short_path=64ec759#L6
also i think border color is not that much important in such preview as for me so for buttons a similar trick can be used (but with BTN_FG instead of FG)
So I've updated the SVG for border colors. Simply making stroke
semi-transparent doesn't look good, so I separated fill
and stroke
.
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="35" viewBox="0 0 120 35">
<defs>
<linearGradient id="bg"><stop stop-color="#DEDEDE"/></linearGradient>
<linearGradient id="button-bg" x2="0" y2="1">
<stop stop-color="#F0F0F0"/>
<stop stop-color="#F0F0F0" offset="1"/>
</linearGradient>
<linearGradient id="button-fg"><stop stop-color="#555555"/></linearGradient>
<linearGradient id="button-border"><stop stop-color="#555555" stop-opacity="0.3"/></linearGradient>
<linearGradient id="checkradio-bg"><stop stop-color="#F9F9F9"/></linearGradient>
<linearGradient id="checkradio-fg"><stop stop-color="#D64937"/></linearGradient>
<linearGradient id="checkradio-border"><stop stop-color="#555555" stop-opacity="0.3"/></linearGradient>
<filter id="drop-shadow" color-interpolation-filters="sRGB" x="-0.5" y="-0.5" width="2" height="2">
<feGaussianBlur in="SourceAlpha" stdDeviation="1"/>
<feOffset dx="0" dy="0.5" result="offsetblur"/>
<feFlood flood-color="#000000" flood-opacity="0.12"/>
<feComposite in2="offsetblur" operator="in"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<rect width="120" height="35" fill="url(#bg)"/>
<g transform="translate(2, 2)" id="button">
<rect x="0" y="0" width="51" height="25" ry="2" fill="url(#button-bg)" filter="url(#drop-shadow)"/>
<rect x="0.5" y="0.5" width="50" height="24" ry="1.5" fill="none" stroke="url(#button-border)" stroke-width="1"/>
<text x="25" y="17" text-anchor="middle" font-family="sans-serif" font-size="9.75pt" fill="url(#button-fg)">Button</text>
</g>
<g transform="translate(60, 6)" id="check">
<rect x="0.5" y="0.5" width="15" height="15" ry="1.5" fill="none" stroke="url(#checkradio-border)"/>
<rect x="1" y="1" width="14" height="14" ry="1" fill="url(#checkradio-bg)"/>
<path d="M11.681 3.928a1.467 1.467 0 0 0-.987.427L6.653 8.2 5.27 6.65c-.494-.659-1.574-.729-2.146-.142-.572.588-.494 1.692.156 2.186l2.39 2.569c.94.94 1.362.814 2.31-.138 0 0 3.258-3.92 5.169-5.243.423-.4.599-.513.376-1.054-.22-.544-1.27-.92-1.845-.9z" fill="url(#checkradio-fg)"/>
</g>
<g transform="translate(86, 6)" id="radio">
<circle cx="8" cy="8" r="7.5" fill="none" stroke="url(#checkradio-border)"/>
<circle cx="8" cy="8" r="7" fill="url(#checkradio-bg)"/>
<circle cx="8" cy="8" r="3" fill="url(#checkradio-fg)"/>
</g>
</svg>
Further update. Simplified the code based on your reply.
(If you don't need a slight drop shadow for the button, please remove the <filter>...</filter>
and filter="url(#drop-shadow)"
.)
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="35" viewBox="0 0 120 35">
<defs>
<linearGradient id="button-bg" x2="0" y2="1">
<stop stop-color="#%BTN_BG%"/>
<stop stop-color="#%BTN_BG%" offset="1"/>
</linearGradient>
<filter id="drop-shadow" color-interpolation-filters="sRGB" x="-0.5" y="-0.5" width="2" height="2">
<feGaussianBlur in="SourceAlpha" stdDeviation="1"/>
<feOffset dx="0" dy="0.5" result="offsetblur"/>
<feFlood flood-color="#000000" flood-opacity="0.12"/>
<feComposite in2="offsetblur" operator="in"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<rect width="120" height="35" fill="#%BG%"/>
<g transform="translate(2, 2)" id="button">
<rect x="0" y="0" width="51" height="25" ry="2" fill="url(#button-bg)" filter="url(#drop-shadow)"/>
<rect x="0.5" y="0.5" width="50" height="24" ry="1.5" fill="none" stroke="#%BTN_FG%" stroke-opacity="0.3" stroke-width="1"/>
<text x="25" y="17" text-anchor="middle" font-family="sans-serif" font-size="9.75pt" fill="#%BTN_FG%">Button</text>
</g>
<g transform="translate(60, 6)" id="check">
<rect x="0.5" y="0.5" width="15" height="15" ry="1.5" fill="none" stroke="#%FG%" stroke-opacity="0.3"/>
<rect x="1" y="1" width="14" height="14" ry="1" fill="#%TXT_BG%"/>
<path d="M11.681 3.928a1.467 1.467 0 0 0-.987.427L6.653 8.2 5.27 6.65c-.494-.659-1.574-.729-2.146-.142-.572.588-.494 1.692.156 2.186l2.39 2.569c.94.94 1.362.814 2.31-.138 0 0 3.258-3.92 5.169-5.243.423-.4.599-.513.376-1.054-.22-.544-1.27-.92-1.845-.9z" fill="#%SEL_BG%"/>
</g>
<g transform="translate(86, 6)" id="radio">
<circle cx="8" cy="8" r="7.5" fill="none" stroke="#%FG%" stroke-opacity="0.3"/>
<circle cx="8" cy="8" r="7" fill="#%TXT_BG%"/>
<circle cx="8" cy="8" r="3" fill="#%SEL_BG%"/>
</g>
</svg>
I hope I made no mistakes...
Also I made the SVG version of metacity-1/thumbnail.png
.
zip is here.
Feel free to use and edit it. :)
so i've came back home and tried to integrate your assets, looks very nice:
btw funny and totally unrelated thing:
$ ll thumbnail.*
.rw-r--r-- 437 lie 17 Jan 21:43 thumbnail.png
.rw-r--r-- 437 lie 17 Jan 21:43 thumbnail.svg
$ file thumbnail.*
thumbnail.png: PNG image data, 100 x 32, 8-bit/color RGBA, non-interlaced
thumbnail.svg: SVG Scalable Vector Graphics image
@nana-4 i've tried using rsvg-convert instead of inkscape and result seems to be fine
the reason was speed, i was thinking if that's possible mb to replace in materia inkscape to rsvg-convert too? from its --help i see it can extract image by id-s as well
btw do you also want to get screenshot-based tests for materia? it helps to see if some change could break some other unexpected widget:
for example one of the previous test results:
https://travis-ci.org/actionless/oomox-gtk-theme/builds/328109403
in the end of the log you could see:
clearlooks gtk2-awf:
https://transfer.sh/gw8MZ/13-15-08_theme-clearlooks-gtk2-awf.test.png
https://transfer.sh/aFZOB/13-15-08_theme-clearlooks-gtk2-awf.orig.png
https://transfer.sh/dwQVc/13-15-08_theme-clearlooks-gtk2-awf.diff.png
I'm glad that it worked well. 😄
i've tried using rsvg-convert instead of inkscape and result seems to be fine
the reason was speed,
Wow, rsvg-convert
has much faster and better font rendering! It looks really nice.
(BTW, not a big matter but it requires additional package for some distros. e.g. librsvg2-tools
for Fedora, librsvg2-bin
for Ubuntu, etc.)
i was thinking if that's possible mb to replace in materia inkscape to rsvg-convert too? from its --help i see it can extract image by id-s as well
That's very interesting, but it seems rsvg-convert
doesn't zoom IDs correctly. :(
This will generate PNG with nothing drawn:
cd materia-theme/src/gtk
rsvg-convert assets.svg -z 2 -i box-shadow -o box-shadow@2.png
I tried other options such as -d
, -p
, -x
, -y
, -w
and -h
, but they also didn't work for IDs.
I guess this is a bug of rsvg-convert
and even if I rewrite the svg, I don't think it will work.
Any ideas?
btw do you also want to get screenshot-based tests for materia? it helps to see if some change could break some other unexpected widget:
Probably I think I don't need the test tool. Because I usually check the changes with gtk3-widget-factory
etc before per commit. But thanks for your kindness. :)
Okay, I figured out a workaround for zooming IDs.
Instead of using -z
option, expand the source SVG itself:
SRC_FILE="assets.svg"
SRC_FILE_2="assets@2.svg"
cp $SRC_FILE $SRC_FILE_2 && \
sed -i -e 's/width="400"/width="800"/1' -e 's/height="400"/height="800"/1' $SRC_FILE_2
rsvg-convert $SRC_FILE_2 -i box-shadow -o box-shadow@2.png
rm $SRC_FILE_2
This will render the zoomed IDs correctly. What do you think?
I usually check the changes with gtk3-widget-factory etc before per commit.
my point was what human could not notice some really small but unwanted change (let's say some single widget lost 1px of its left padding) while using compare
tool for making image diffs will highlight all such cases. that's became even more important when testing theme generation with different colors, because some change which looks good in light colors could look bad in dark colorscheme and the opposite
This will render the zoomed IDs correctly. What do you think?
if it's working correctly but faster -- why not to use it? :)
Thanks. So, when I solve other minor bug, I'll use rsvg-convert
for Materia. :)
(However, I'm going to remove GNU parallel because rsvg-convert
with parallel
causes errors irregularly.)
About the tests,
So, how can I get it? If handling is easier I would like to use it. :)
how can i reproduce the issue with parallel
?
re: tests:
it's quite simple flow:
-
first docker builds an image with all dependencies which i need for generating the theme:
https://github.com/actionless/oomox-gtk-theme/blob/master/.travis.yml#L13
https://github.com/actionless/oomox-gtk-theme/blob/master/Dockerfile -
next i am running my test script inside that docker container:
https://github.com/actionless/oomox-gtk-theme/blob/master/.travis.yml#L16
https://github.com/actionless/oomox-gtk-theme/blob/master/test/all_tests.sh
2.1) here i am generating/building the themes:
https://github.com/actionless/oomox-gtk-theme/blob/master/test/all_tests.sh#L59-L73
2.2) next running the tests:
https://github.com/actionless/oomox-gtk-theme/blob/master/test/all_tests.sh#L82-L92
https://github.com/actionless/oomox-gtk-theme/blob/master/test/test.sh
2.2.a) choosing generated GTK theme in settings:
https://github.com/actionless/oomox-gtk-theme/blob/master/test/test.sh#L36-L50
2.2.b) starting Xvfb and inside gtk widget factory, making screenshot, compare output:
https://github.com/actionless/oomox-gtk-theme/blob/master/test/test.sh#L167-L173
MISC:
how to generate reference screenshots:
https://github.com/actionless/oomox-gtk-theme#hacking
also for local development of screenshot-based tests it's usable to have git diff
extension like that:
http://www.akikoskinen.info/image-diffs-with-git/
i had some display artifacts with display
app ( :-) ) used in the example, so using different image viewer: https://github.com/actionless/dotfiles/blob/master/misc/bin/git-imgdiff
you can reuse most of the testcode, just update the dependencies, theme name in docker paths and test results screenshots
also a good improvement could be to use ubuntu or debian as a base in tests' docker container instead of arch:
because arch is rolling, on almost every freetype (or other font-rendering-related) package update i have to regenerate screenshots because some characters are rendering differently now
how can i reproduce the issue with parallel?
Please copy and paste the following to materia-theme/src/gtk/render-asset.sh
#! /bin/bash
set -ueo pipefail
RSVG_CONVERT="/usr/bin/rsvg-convert"
OPTIPNG="/usr/bin/optipng"
SRC_FILE="assets.svg"
SRC_FILE_2="assets@2.svg"
ASSETS_DIR="assets"
i=${1}
cp $SRC_FILE $SRC_FILE_2 && sed -i -e 's/width="400"/width="800"/1' -e 's/height="400"/height="800"/1' $SRC_FILE_2
if [ -f $ASSETS_DIR/$i.png ]; then
echo $ASSETS_DIR/$i.png exists.
else
echo Rendering $ASSETS_DIR/$i.png
$RSVG_CONVERT --export-id=$i \
--output=$ASSETS_DIR/$i.png $SRC_FILE >/dev/null \
&& $OPTIPNG -o7 --quiet $ASSETS_DIR/$i.png
fi
if [ -f $ASSETS_DIR/$i@2.png ]; then
echo $ASSETS_DIR/$i@2.png exists.
else
echo Rendering $ASSETS_DIR/$i@2.png
$RSVG_CONVERT --export-id=$i \
--output=$ASSETS_DIR/$i@2.png $SRC_FILE_2 >/dev/null \
&& $OPTIPNG -o7 --quiet $ASSETS_DIR/$i@2.png
fi
exit 0
then run: rm assets/*.png && ./render-assets.sh
At least in my environment (rsvg-convert version 2.40.20
), like the following logs are irregularly outputed and 0 byte
PNGs are generated. It seems all errors are only in *@2.png
.
Rendering assets/radio-checked-dark@2.png
Error reading SVG:Input file is too short
Rendering assets/checkbox-unchecked-hover@2.png
Error reading SVG:Error domain 1 code 77 on line 285 column 7 of data: Premature end of data in tag svg line 1
re:re:tests:
Thanks a lot! I'll check them in detail later. :)
right, because 4 (or whatever is yours nproc
) different scripts at the same time trying to create assets@2.svg
to avoid that it could be two possible solutions:
- "convert"
assets.svg
toassets@2.svg
only once, before runningrender-asset.sh
(ie inrender-assets.sh
) - replace
SRC_FILE_2="assets@2.svg"
toSRC_FILE_2="$(mktemp XXXXXXX.svg)"
and clean-up that file in the end of render-asset.sh
i prefer the first way but it could make things harder for testing mb
also if you make it to work it will be interesting to measure the time difference
Errors are gone! Thank you for your insight. :)
I will apply the first way.
i've measured average generation time for gnome-colors icons:
inkscape no parallel:
85.93
inkscape nproc (4):
34.48
rsvg no parallel:
17.35
rsvg nproc (4):
8.62
Thanks for this!
However, after testing, it turned out that migration is difficult with Materia due to some rendering bugs. :(
I'm going to open an issue to materia-theme
repo and point out the rendering issues later.
btw could you show some rendering errors examples?
also, are they happening for both normal and @2
assets?
@actionless I'm sorry for the late response.
Now I've opened a new issue and shown examples of bugs: nana-4/materia-theme#202
They are happening for both normal and @2
assets, but they are not @2
specific problems.