Shake is quite amazing: powered by Haskell, it's really easy to quickly throw together build rules for little problems that appear in everyday programming tasks.
Here's a small snippet of Shake rules that convert an SVG to an iOS application icon in the various required sizes. As a bonus point, it generates icons for different build configurations by showing and hiding layers using inkscape-export-layers. See this article for how to use the different icons sets.
-- Generate iOS icons from SVG
iosIcons :: String -> Rules ()
iosIcons target = do
let resolutions = [(29,[1,2,3]), (40,[1,2,3]), (50,[1,2]), (57,[1,2]), (60,[2,3]), (72,[1,2]), (76,[1,2])]
configurations = [Beta, Debug, Release]
icon size mul config = buildDir </> "ios/icons"
</> "LocosonicPlayer" ++ show config
</> "AppIcon" ++ show size ++ "x" ++ show size ++ (if mul /= 1 then "@" ++ show mul else "") ++ ".png"
forM_ resolutions $ \(size,muls) -> do
forM_ configurations $ \config -> do
forM_ muls $ \mul -> do
icon size mul config %> \png -> do
pwd <- liftIO Dir.getCurrentDirectory
let input = "assets/LocosonicPlayer/locosonic_app_icon.svg"
need [input]
withTempFile $ \svg -> do
let badge config = show config ++ " badge"
toShow = [badge config, "Icon", "Square background"]
toHide = map badge (delete config configurations) ++ ["Rounded background"]
() <- cmd "./tools/inkscape-export-layers/exportlayers.py" $
concatMap (\layer -> ["--show", layer]) toShow
++ concatMap (\layer -> ["--hide", layer]) toHide
++ [input, svg]
let width = size * mul
height = width
cmd "inkscape" [
"--export-png", pwd </> png,
"--export-area-page",
"--export-width", show width,
"--export-height", show height,
pwd </> svg ]
phony target $ need $ concat [ [ icon s m c | m <- ms ] | (s,ms) <- resolutions, c <- configurations ]
And just for fun, the same for Android:
-- Generate Android icons from SVG
androidIcons :: String -> Rules ()
androidIcons target = do
let resolutions = ["hdpi", "mdpi", "xhdpi", "xxhdpi", "xxxhdpi"]
configurations = [Beta, Debug]
icon res config = buildDir </> "android/icons"
</> "LocosonicPlayer" ++ show config
</> "res" </> ("drawable-" ++ res)
</> "ic_launcher.png"
forM_ resolutions $ \res -> do
forM_ configurations $ \config -> do
icon res config %> \png -> do
pwd <- liftIO Dir.getCurrentDirectory
let input = "assets/LocosonicPlayer/locosonic_app_icon.svg"
need [input]
withTempFile $ \svg -> do
let badge config = show config ++ " badge"
toShow = [badge config, "Icon", "Rounded background"]
toHide = map badge (delete config configurations) ++ ["Square background"]
() <- cmd "./tools/inkscape-export-layers/exportlayers.py" $
concatMap (\layer -> ["--show", layer]) toShow
++ concatMap (\layer -> ["--hide", layer]) toHide
++ [input, svg]
let (width,height) = iconSize res
cmd "inkscape" [
"--export-png", pwd </> png,
"--export-area-drawing",
"--export-width", show width,
"--export-height", show height,
pwd </> svg ]
phony target $ need $ [ icon r c | r <- resolutions, c <- configurations ]
where
iconSize res = case res of
"mdpi" -> (48,48)
"hdpi" -> (72,72)
"xhdpi" -> (96,96)
"xxhdpi" -> (144,144)
"xxxhdpi" -> (192,192)
_ -> error $ "Unknown resolution " ++ res
Comments welcome! @kaoskorobase