From 1922bf05254b464725c456740a8ddca2edd687ab Mon Sep 17 00:00:00 2001 From: Christer Jensen Date: Wed, 30 Aug 2017 19:46:22 +0200 Subject: [PATCH 1/4] Improve render script performance The script no longer creates a new inkscape process for every png export. Instead a single inkscape process is created for each svg-file and export commands are simply fed to it. This allows for using multiple CPU-cores and avoids the cost of constantly starting up inkscape. The script no longer renders out the entire icon set each time it's run, instead it updates only icons which have been changed since the last time the script finished running. This also means if the script is interrupted while rendering, any svg-files what was finished will not render out again saving time. --- .gitignore | 1 + src/render_icons.sh | 98 +++++++++++++++++++++++++-------------------- 2 files changed, 55 insertions(+), 44 deletions(-) mode change 100644 => 100755 src/render_icons.sh diff --git a/.gitignore b/.gitignore index 05b994c..f256c54 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ configure install-sh missing *.tmp +*_timestamp diff --git a/src/render_icons.sh b/src/render_icons.sh old mode 100644 new mode 100755 index 9152e8d..3864c08 --- a/src/render_icons.sh +++ b/src/render_icons.sh @@ -1,7 +1,6 @@ #!/bin/bash INKSCAPE="/usr/bin/inkscape" -OPTIPNG="/usr/bin/optipng" pushd `dirname $0` > /dev/null DIR="$( cd "$(dirname "$0")" ; pwd -P )" @@ -9,62 +8,73 @@ popd > /dev/null cd ${DIR} +TYPES=(actions apps categories devices emblems mimetypes places status) +SIZES=(16 22 24 32 48 64 96 128) + THEMEDIR=../Arc -mkdir -p $THEMEDIR +# Set up all the folders in the theme directory. +mkdir -p $THEMEDIR/{actions,apps,categories,devices,emblems,mimetypes,places,status}/{16,22,24,32,48,64,96,128}{,@2x} + +cp -u index.theme $THEMEDIR/index.theme -for CONTEXT in actions apps categories devices emblems mimetypes places status +for CONTEXT in ${TYPES[@]} do + for SIZE in ${SIZES[@]} + do + cp -ru $CONTEXT/symlinks/* $THEMEDIR/$CONTEXT/$SIZE + cp -ru $CONTEXT/symlinks/* $THEMEDIR/$CONTEXT/$SIZE@2x + cp -ru $CONTEXT/symbolic $THEMEDIR/$CONTEXT + done +done - mkdir -p $THEMEDIR/$CONTEXT - mkdir -p $THEMEDIR/$CONTEXT +rm -rf $THEMEDIR/actions/{32,32@2x,48,48@2x,64,64@2x,96,96@2x,128,128@2x} # derp - cp -r $CONTEXT/symbolic $THEMEDIR/$CONTEXT +# TODO +cp -ru animations $THEMEDIR/. +cp -ru panel $THEMEDIR/. - for SIZE in 16 22 24 32 48 64 96 128 - do - $INKSCAPE -S $CONTEXT.svg | grep -E "_$SIZE" | sed 's/\,.*$//' > index.tmp - mkdir -p $THEMEDIR/$CONTEXT/$SIZE - mkdir -p $THEMEDIR/$CONTEXT/$SIZE@2x +# Generates inkscape export commands for the given +# svg-file that can be piped to inkscape. +genInkscapeCmds() { - cp -r $CONTEXT/symlinks/* $THEMEDIR/$CONTEXT/$SIZE - cp -r $CONTEXT/symlinks/* $THEMEDIR/$CONTEXT/$SIZE@2x + local CONTEXT=$1 - for OBJECT_ID in `cat index.tmp` + for SIZE in ${SIZES[@]} + do + echo "Rendering icons $CONTEXT.svg @$SIZE" >&2 + for OBJECT_ID in `cat <($INKSCAPE -S $CONTEXT.svg | grep -E "_$SIZE" | sed 's/\,.*$//')` do - - ICON_NAME=$(sed "s/\_$SIZE.*$//" <<< $OBJECT_ID) - - if [ -f $THEMEDIR/$CONTEXT/$SIZE/$ICON_NAME.png ]; then - echo $THEMEDIR/$CONTEXT/$SIZE/$ICON_NAME.png exists. - else - echo - echo Rendering $THEMEDIR/$CONTEXT/$SIZE/$ICON_NAME.png - $INKSCAPE --export-id=$OBJECT_ID \ - --export-id-only \ - --export-png=$THEMEDIR/$CONTEXT/$SIZE/$ICON_NAME.png $CONTEXT.svg >/dev/null \ - && $OPTIPNG -o7 --quiet $ASSETS_DIR/$i.png - fi - if [ -f $THEMEDIR/$CONTEXT/$SIZE@2x/$ICON_NAME.png ]; then - echo $THEMEDIR/$CONTEXT/$SIZE@2x/$ICON_NAME.png exists. - else - echo - echo Rendering $THEMEDIR/$CONTEXT/$SIZE@2x/$ICON_NAME.png - $INKSCAPE --export-id=$OBJECT_ID \ - --export-dpi=180 \ - --export-id-only \ - --export-png=$THEMEDIR/$CONTEXT/$SIZE@2x/$ICON_NAME.png $CONTEXT.svg >/dev/null \ - && $OPTIPNG -o7 --quiet $ASSETS_DIR/$i@2.png - fi + local ICON_NAME=$(sed "s/\_$SIZE.*$//" <<< $OBJECT_ID) + + echo \ + "--export-id=$OBJECT_ID" \ + "--export-id-only" \ + "--export-png=$THEMEDIR/$CONTEXT/$SIZE/$ICON_NAME.png $CONTEXT.svg" + + echo \ + "--export-id=$OBJECT_ID" \ + "--export-dpi=180" \ + "--export-id-only" \ + "--export-png=$THEMEDIR/$CONTEXT/$SIZE@2x/$ICON_NAME.png $CONTEXT.svg" done done +} + +for CONTEXT in ${TYPES[@]} +do + # Only render out the icons if the svg-file has been modified + # since we finished rendering it out last. + if [[ $CONTEXT.svg -nt .${CONTEXT}_timestamp ]] + then + genInkscapeCmds $CONTEXT | $INKSCAPE --shell > /dev/null && touch .${CONTEXT}_timestamp & + else + echo "No changes to $CONTEXT.svg, skipping..." + fi done -rm index.tmp -cp index.theme $THEMEDIR/index.theme -rm -rf $THEMEDIR/actions/{32,32@2x,48,48@2x,64,64@2x,96,96@2x,128,128@2x} # derp +wait -# TODO -cp -r animations $THEMEDIR/. -cp -r panel $THEMEDIR/. +# Remove all empty directories from the theme folder. +find $THEMEDIR -type d -empty -delete From 525b4a26637369fc42ee368aa03e3ae69eb08ffb Mon Sep 17 00:00:00 2001 From: Christer Jensen Date: Thu, 31 Aug 2017 06:17:20 +0200 Subject: [PATCH 2/4] Improve performance by dividing up tasks The stream of inkscape commands have been divided across multiple instances of inkscape, one per core. This speeds up rendering by using more cpu cores, even for single svg rendering. To do this a simple java program was written which starts N instances of whatever arguments was passed to it and then reads one line at the time from standard input, the lines are then divided into N seperate streams which are then piped to the the difference instances of whatever program was passed as argument to SplitJob. --- src/SplitJob.class | Bin 0 -> 2401 bytes src/SplitJob.java | 54 ++++++++++++++++++++++++++++++++++++++++++++ src/render_icons.sh | 5 ++-- 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/SplitJob.class create mode 100644 src/SplitJob.java diff --git a/src/SplitJob.class b/src/SplitJob.class new file mode 100644 index 0000000000000000000000000000000000000000..10c467d6727cc7fa6cde72fba3d713f1b54d0144 GIT binary patch literal 2401 zcma)8%Xbr182?R^$xX&7g|=xMEKnZB6fBhjRnzinDH1F#HVDRwGEJssAWh;c zimx<;5Yf<$9!a(f>=4+gLB*~BcB5DB`Xt#CzD%1t7DFlIC;Rx7WD;= z3s?dth>pNX=B&WqlSsL-v{)u@C(ON;^jsawrYvWFW^|KGQpW~tq^*t=CUm5cQLwC- zeKF!eJCiVTIhJ$>uQzX{Sd($YEzJ{XZ9o<$CnioXV*}TKrO=F@o2@;-5 z61p!W`I6n5?+O#SOUoBEWjLR9tO>TVzEaa|6=$rX;u78pv~kl}Fbjs;Du&8s)2@#5 zV5Q{zxxO+sJI_IlDp*}c#}&FwTsLecEt{~ihVoXArqia~mojoWlRiXra9{s$^pJwJ z6_NkN5i_agktsSY_E^Er@c%HYENZc9dQ@|cVKc|YwYzGR``MeMJcUGc5j^ghaXvfF zTcw17>gUI;lF!m7ZOdU@B0SO?jmpbI9ZThN$GIj_nVghN8kVy+V=o?^GdahcVE;{< zf?%lu40@1vkUPtaS#eiH(~dcAQdgWZQh9S|OkQ8n%Fb&UUF&bKkW`)R20;%jfA5K@s#_Mqfw`iq42X@bb`k6GH5>H}TQ$ul&9F&7)B7*v-{8NLo7jxs(5WccqNv!02N-c5 zv^lJUPhhj4NMMV=R`&Ey)Zaptatk#A+y21z+t4Uel)tcRj{jr4WqqJmpsN*rJh(6z u?NpJ!;4Id}XR$Uujde3Uo2y1}cGJPL-oW2 /dev/null && touch .${CONTEXT}_timestamp & + echo "Rendering icons from $CONTEXT.svg" + genInkscapeCmds $CONTEXT | java SplitJob $INKSCAPE --shell && touch .${CONTEXT}_timestamp else echo "No changes to $CONTEXT.svg, skipping..." fi done -wait - # Remove all empty directories from the theme folder. find $THEMEDIR -type d -empty -delete From d37d54fd87b793471b3847ac1c3b93583e1dedd3 Mon Sep 17 00:00:00 2001 From: Christer Jensen Date: Sat, 2 Sep 2017 17:27:43 +0200 Subject: [PATCH 3/4] Add filtered rendering Instead of rendering out everything in an svg-file, the render script now takes in a regular expression that is uses to search all the object-IDs inside each of the svg-files for a match and only renders those. To make the search go faster all object-IDs are stored in files named "..cache" after every full render of an svg-file or if none exist. --- .gitignore | 1 + src/render_icons.sh | 92 +++++++++++++++++++++++++++++++++------------ 2 files changed, 68 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index f256c54..9434000 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ install-sh missing *.tmp *_timestamp +*.cache diff --git a/src/render_icons.sh b/src/render_icons.sh index 29a6fe2..a508c74 100755 --- a/src/render_icons.sh +++ b/src/render_icons.sh @@ -35,6 +35,29 @@ cp -ru animations $THEMEDIR/. cp -ru panel $THEMEDIR/. +# Takes in an svg-file and an object-id and formats it +# to an inkscape export shell command that inkscape can +# then execute. +formatInkscapeCmd() { + + local CONTEXT=$1 + local OBJECT_ID=$2 + local SIZE=$(sed -r 's/.*\_([0-9]+).*$/\1/' <<< $OBJECT_ID) + + local ICON_NAME=$(sed "s/\_$SIZE.*$//" <<< $OBJECT_ID) + + echo \ + "--export-id=$OBJECT_ID" \ + "--export-id-only" \ + "--export-png=$THEMEDIR/$CONTEXT/$SIZE/$ICON_NAME.png $CONTEXT.svg" + + echo \ + "--export-id=$OBJECT_ID" \ + "--export-dpi=180" \ + "--export-id-only" \ + "--export-png=$THEMEDIR/$CONTEXT/$SIZE@2x/$ICON_NAME.png $CONTEXT.svg" +} + # Generates inkscape export commands for the given # svg-file that can be piped to inkscape. genInkscapeCmds() { @@ -43,37 +66,56 @@ genInkscapeCmds() { for SIZE in ${SIZES[@]} do - echo "Rendering icons $CONTEXT.svg @$SIZE" >&2 for OBJECT_ID in `cat <($INKSCAPE -S $CONTEXT.svg | grep -E "_$SIZE" | sed 's/\,.*$//')` do - local ICON_NAME=$(sed "s/\_$SIZE.*$//" <<< $OBJECT_ID) - - echo \ - "--export-id=$OBJECT_ID" \ - "--export-id-only" \ - "--export-png=$THEMEDIR/$CONTEXT/$SIZE/$ICON_NAME.png $CONTEXT.svg" - - echo \ - "--export-id=$OBJECT_ID" \ - "--export-dpi=180" \ - "--export-id-only" \ - "--export-png=$THEMEDIR/$CONTEXT/$SIZE@2x/$ICON_NAME.png $CONTEXT.svg" + echo $OBJECT_ID >> .$CONTEXT.cache.tmp + formatInkscapeCmd $CONTEXT $OBJECT_ID done done + mv .$CONTEXT.cache.tmp .$CONTEXT.cache } -for CONTEXT in ${TYPES[@]} -do - # Only render out the icons if the svg-file has been modified - # since we finished rendering it out last. - if [[ $CONTEXT.svg -nt .${CONTEXT}_timestamp ]] - then - echo "Rendering icons from $CONTEXT.svg" - genInkscapeCmds $CONTEXT | java SplitJob $INKSCAPE --shell && touch .${CONTEXT}_timestamp - else - echo "No changes to $CONTEXT.svg, skipping..." - fi -done +# Generates inkscape export commands that matches +# the provided regex pattern. +genInkscapeCmdsFiltered() { + + local CONTEXT=$1 + local REGEX=$2 + + while read -r OBJECT_ID + do + echo "Match: $OBJECT_ID" >&2 + formatInkscapeCmd $CONTEXT $OBJECT_ID + done < <(grep -E $REGEX .$CONTEXT.cache) +} +if [[ ! -z $1 ]] +then + echo "Rendering objects with IDs matching regex" + for CONTEXT in ${TYPES[@]} + do + if [[ -f .$CONTEXT.cache ]] || { [[ ! -f .$CONTEXT.cache ]] && ($INKSCAPE -S $CONTEXT.svg | grep -E "_[0-9]+" | sed 's/\,.*$//' > .$CONTEXT.cache.tmp); } + then + mv .$CONTEXT.cache.tmp .$CONTEXT.cache 2> /dev/null + genInkscapeCmdsFiltered $CONTEXT $1 | java SplitJob $INKSCAPE --shell + else + echo "Failed creating creating object-ID cache for $CONTEXT.svg" + fi + done +else + for CONTEXT in ${TYPES[@]} + do + # Only render out the icons if the svg-file has been modified + # since we finished rendering it out last. + if [[ $CONTEXT.svg -nt .${CONTEXT}_timestamp ]] + then + echo "Rendering icons from $CONTEXT.svg" + genInkscapeCmds $CONTEXT | java SplitJob $INKSCAPE --shell && touch .${CONTEXT}_timestamp + else + echo "No changes to $CONTEXT.svg, skipping..." + fi + done +fi + # Remove all empty directories from the theme folder. find $THEMEDIR -type d -empty -delete From b2167d8a44933192978ec2d71828daba244e2059 Mon Sep 17 00:00:00 2001 From: Christer Jensen Date: Sat, 8 Sep 2018 01:05:57 +0200 Subject: [PATCH 4/4] Change location of cache/timestamp files All cache and timestamp files are now in a single directory named .cache avoiding clutter in the src directory and makes delete cache files easier. --- src/render_icons.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/render_icons.sh b/src/render_icons.sh index a508c74..bbbe079 100755 --- a/src/render_icons.sh +++ b/src/render_icons.sh @@ -34,6 +34,8 @@ rm -rf $THEMEDIR/actions/{32,32@2x,48,48@2x,64,64@2x,96,96@2x,128,128@2x} # derp cp -ru animations $THEMEDIR/. cp -ru panel $THEMEDIR/. +# Ensure cache folder exists +mkdir .cache # Takes in an svg-file and an object-id and formats it # to an inkscape export shell command that inkscape can @@ -68,11 +70,11 @@ genInkscapeCmds() { do for OBJECT_ID in `cat <($INKSCAPE -S $CONTEXT.svg | grep -E "_$SIZE" | sed 's/\,.*$//')` do - echo $OBJECT_ID >> .$CONTEXT.cache.tmp + echo $OBJECT_ID >> .cache/$CONTEXT.cache.tmp formatInkscapeCmd $CONTEXT $OBJECT_ID done done - mv .$CONTEXT.cache.tmp .$CONTEXT.cache + mv .cache/$CONTEXT.cache.tmp .cache/$CONTEXT.cache } # Generates inkscape export commands that matches @@ -86,7 +88,7 @@ genInkscapeCmdsFiltered() { do echo "Match: $OBJECT_ID" >&2 formatInkscapeCmd $CONTEXT $OBJECT_ID - done < <(grep -E $REGEX .$CONTEXT.cache) + done < <(grep -E $REGEX .cache/$CONTEXT.cache) } if [[ ! -z $1 ]] @@ -94,9 +96,9 @@ then echo "Rendering objects with IDs matching regex" for CONTEXT in ${TYPES[@]} do - if [[ -f .$CONTEXT.cache ]] || { [[ ! -f .$CONTEXT.cache ]] && ($INKSCAPE -S $CONTEXT.svg | grep -E "_[0-9]+" | sed 's/\,.*$//' > .$CONTEXT.cache.tmp); } + if [[ -f .cache/$CONTEXT.cache ]] || { [[ ! -f .cache/$CONTEXT.cache ]] && ($INKSCAPE -S $CONTEXT.svg | grep -E "_[0-9]+" | sed 's/\,.*$//' > .cache/$CONTEXT.cache.tmp); } then - mv .$CONTEXT.cache.tmp .$CONTEXT.cache 2> /dev/null + mv .cache/$CONTEXT.cache.tmp .cache/$CONTEXT.cache 2> /dev/null genInkscapeCmdsFiltered $CONTEXT $1 | java SplitJob $INKSCAPE --shell else echo "Failed creating creating object-ID cache for $CONTEXT.svg" @@ -107,10 +109,10 @@ else do # Only render out the icons if the svg-file has been modified # since we finished rendering it out last. - if [[ $CONTEXT.svg -nt .${CONTEXT}_timestamp ]] + if [[ $CONTEXT.svg -nt .cache/${CONTEXT}_timestamp ]] then echo "Rendering icons from $CONTEXT.svg" - genInkscapeCmds $CONTEXT | java SplitJob $INKSCAPE --shell && touch .${CONTEXT}_timestamp + genInkscapeCmds $CONTEXT | java SplitJob $INKSCAPE --shell && touch .cache/${CONTEXT}_timestamp else echo "No changes to $CONTEXT.svg, skipping..." fi