|
|
#!/bin/sh -e
#===============================================================
# Filename : prepare
# Purpose : Prepare wallpapers for Adélie desktop environments.
# Authors : Zach van Rijn <me@zv.io>
# License : Apache 2.0
# Revision : 20231205
#===============================================================
#===============================================================
# README
#===============================================================
##
# This script transforms source images, including Adélie logos,
# into a set of wallpapers suitable for packaging.
#
# There are two distinct output products:
#
# (1) a "core" or "slim" bundle, containing a lightweight set of
# default wallpaper(s) and/or branding; and
#
# (2) a "full" bundle containing all available wallpapers, which
# is suitable for use when disk space isn't a major concern.
#
#
#
# requirements
# ------------
#
# * imagemagick
#
#
# usage
# -----
#
# To process all source images and generate a tarball for upload
# to 'distfiles', simply run the following command:
#
# $ ./prepare
#
# Any tarball of the same name will be silently overwritten.
#
#---------------------------------------------------------------
# configuration: source image input
#---------------------------------------------------------------
##
# Distfiles mirror.
#
HOST="https://distfiles.adelielinux.org";
##
# Adélie brand asset bundle version.
#
# This corresponds to the commit of 'adelie/site-ng' from which
# the brand assets were generated. A tarball matching this hash
# must exist in the '<HOST>/source/site-ng-images/' directory.
#
# See https://git.adelielinux.org/adelie/site-ng for details.
#
HASH=ca57e2bd46f11bf2efdebbca8c7813235744fd5f;
##
# Name of the containing directory and tarball on distfiles.
#
NAME="site-ng-images";
#---------------------------------------------------------------
# configuration: processed image output
#---------------------------------------------------------------
##
# Name of output directory. Please ensure it is in '.gitignore'.
#
KEEP="output";
##
# Choose an output file type.
#
TYPE="jpg";
##
# Table of aspect ratios to generate wallpapers for.
#
# Format: RATIO SCALE [SCALE ...]
#
# Scale is distributed, e.g.:
#
# "4:3 640" --> (640*4)x(640*3) = 2560x1920
#
# Note that many popular aspect ratios are approximate. We are
# only concerned with getting to the right ballpark.
#
# Table rows MUST BE SORTED FROM GREATEST TO LEAST.
#
MAKE=$(grep -v ^# <<EOF
21:9 122
16:10 160 120 105 80
16:9 240 160 120 90
8:5 200
5:4 480 256
4:3 640 400 256 200
3:2 854
EOF
);
##
# Y-axis menu bar offset (maximum).
#
MENU=100;
#---------------------------------------------------------------
# internal: meta
#---------------------------------------------------------------
HERE="$(dirname $(readlink -f ${0}))";
cd "${HERE}";
##
# Check for required tools.
#
for k in curl gm; do
if ! command -v ${k} 2>&1 >/dev/null; then
printf "E: required utility '%s' not found!\n" "${k}";
exit 1;
fi
done
##
# Tag first, then generate release the tarball. Sanity checks do
# not prevent someone from being stupid, but they can avoid some
# common errors. We want to reduce surprises/ensure consistency.
#
if test "${1}" = "--test"; then
VTAG="DEV";
else
VTAG=$(git describe --tags --abbrev=0 2>/dev/null || true);
if test -z "${VTAG}"; then
printf "E: you need to tag at least one commit!\n";
exit 1;
fi
if test $(git rev-list ${VTAG}..HEAD | wc -l) -gt 0; then
printf "E: you need to be checked out at a tag!\n";
exit 1;
fi
if test $(git ls-remote --tags origin ${VTAG} | wc -l) -eq 0; then
printf "E: tag '%s' does not exist on origin!\n" "${VTAG}";
exit 1;
fi
if test $(git status --porcelain | wc -l) -gt 0; then
printf "E: tree is not clean; aborting!\n" "${VTAG}";
exit 1;
fi
fi
##
# Name of build directory. Please ensure it is in '.gitignore'.
#
TEMP="build";
##
# Name of source directory.
#
IMGS="src";
##
# Ensure that no images have conflicting names.
#
# FIXME: factor out 'background lockscreen' here and elsewhere.
#
for k in background lockscreen; do
if test -d "${IMGS}"/${k}; then
printf "E: not allowed to name image '%s'!\n" "${k}";
exit 1;
fi
done
#---------------------------------------------------------------
# internal: support routines
#---------------------------------------------------------------
##
# size_only DIR RATIO SCALE [SCALE ...]
#
size_only ()
{
data="${1}"; shift;
size="${1}"; shift;
from="${1}"; # NO SHIFT
list="${@}";
##
# FIXME: assumes 'a:b' where 'a' and 'b' are integers. This
# should check that this actually holds.
#
case "${size}" in
*:*)
;;
*)
printf "E: invalid aspect ratio '%s'!\n" "${size}";
exit 1;
;;
esac
##
# Generated images have known sizes that do not change.
#
from_x=$((${from}*${size%:*}));
from_y=$((${from}*${size#*:}));
printf "Processing %s...\n" "${size}";
find "${data}" -mindepth 1 -maxdepth 1 -type d | sort | while read image; do
name=$(printf "%s\n" "${image}" | cut -d/ -f3); # sloppy, sorry
case "${name}" in
background|lockscreen)
type="png"; # override for quality
;;
*)
type="${TYPE}";
;;
esac
printf " * %s\n" "${name}";
mkdir -p "${KEEP}"/${name};
for k in ${list}; do
x=$((${k}*${size%:*}));
y=$((${k}*${size#*:}));
printf " - Generating %4sx%4s (scale: %s)\n" "${x}" "${y}" "${k}";
# resized
gm convert "${image}/${from_x}x${from_y}.png" -resize ${x}x${y}^ "${KEEP}"/${name}/${x}x${y}.${type} 2>/dev/null;
done
done
}
#---------------------------------------------------------------
# internal: core
#---------------------------------------------------------------
mkdir -p "${HERE}/${TEMP}";
rm -fr "${HERE}"/${KEEP};
mkdir "${HERE}/${KEEP}";
##
# Fetch the specified brand asset bundle from distfiles.
#
# TODO: error checking, return codes etc.
#
(
cd "${TEMP}";
if ! test -e ${NAME}-${HASH}.tar.gz; then
curl -O "${HOST}"/source/${NAME}/${NAME}-${HASH}.tar.gz;
fi
tar -xf ${NAME}-${HASH}.tar.gz;
)
#---------------------------------------------------------------
# internal: generate minimal wallpapers
#---------------------------------------------------------------
##
# The default "core" or "slim" wallpaper is made on the fly and
# not provided as a rasterized image from the start.
#
# Discrete conversion steps are used for clarity of intent, even
# though the same effect can be achieved by combining steps.
#
# FIXME: the 'MENU' padding needs to be 100px after resizing; we
# currently do it before resizing. So we have to do a "reverse"
# calculation to determine what is the equivalent of 100px for
# the shortest target size for each aspect ratio. 100px is also
# just an estimate and is not based on actual facts.
#
##
# make_fake GRADIENT_FROM GRADIENT_TO XxY TEMPLATE OUTPUT [ARGS]
#
make_fake ()
{
size="${1}"; shift; # geometry
hexa="${1}"; shift; # gradient from
hexb="${1}"; shift; # gradient to
temp="${1}"; shift; # template
name="${1}"; shift; # output filename
args="${@}"; # all remaining arguments
printf "Generating %5s ('%s')...\n" "${size}" "${name}";
# generate gradient brackground of correct size
gm convert \
-define gradient:direction=NorthEast \
-size ${size} \
gradient:"${hexa}"-"${hexb}" \
"${name}" \
;
# polyguin scaled to 80% of Y-MENU, translated +MENU
gm convert \
-background none \
-resize ${size%x*}x$(((${size#*x}-${MENU})*80/100)) \
"${TEMP}"/polyguin.svg \
"${name}.tmp.png" \
;
gm composite \
-compose atop \
-gravity southwest \
"${name}.tmp.png" \
-geometry +0+${MENU} \
"${name}" \
"${name}" \
;
# polylogo scaled to 10% of Y-MENU, translated +MENU
gm convert \
-background none \
-resize ${size%x*}x$(((${size#*x}-${MENU})*10/100)) \
"${TEMP}"/gen_polylogo_template_${temp}.png \
"${name}.tmp.png" \
;
gm composite \
-compose atop \
-gravity southeast \
"${name}.tmp.png" \
-geometry +50+${MENU} \
"${name}" \
"${name}" \
;
rm "${name}.tmp.png";
# apply any custom transformations
gm convert \
${args} \
"${name}" \
"${name}" \
;
}
##
# Generate starting templates. That is, generate the largest one
# possible for each aspect ratio.
#
printf "%s\n" "${MAKE}" | while read ratio scale _; do
# compute largest required
x=$((${scale}*${ratio%:*}));
y=$((${scale}*${ratio#*:}));
# background (monochrome)
mkdir -p "${TEMP}"/generated/background;
make_fake ${x}x${y} \
"#777777" "#dddddd" \
black_x200 \
"${TEMP}"/generated/background/${x}x${y}.png \
-colorspace Gray \
;
# lockscreen (full color)
mkdir -p "${TEMP}"/generated/lockscreen;
make_fake ${x}x${y} \
"#111111" "#444444" \
white_x200 \
"${TEMP}"/generated/lockscreen/${x}x${y}.png \
;
done
#---------------------------------------------------------------
# internal: scale all wallpapers
#---------------------------------------------------------------
##
# To generate "real" wallpapers, we simply resize them. This can
# be be improved significantly, but that is a future problem.
#
make_real ()
{
size="${1}"; shift; # geometry
temp="${1}"; shift; # template
name="${1}"; shift; # output filename
# TODO: add filename extension checker?
printf "Generating %5s ('%s')...\n" "${size}" "${name}";
gm convert "${file}" -resize ${size}^ "${name}" 2>/dev/null;
}
##
# Source images may not all be consistent in their aspect ratios
# or dimensions. We will scale (crop) source images to match the
# sizes of the generated core templates.
#
printf "%s\n" "${MAKE}" | while read ratio scale _; do
# compute largest required
x=$((${scale}*${ratio%:*}));
y=$((${scale}*${ratio#*:}));
find "${IMGS}" -mindepth 1 -maxdepth 1 -type d | sort | while read k; do
file="$(find ${k} -type f -name 'image.*')";
if test $(printf "%s\n" "${file}" | wc -l) -ne 1; then
printf "E: not exactly one image at '%s'!\n" "${k}";
exit 1;
fi
# FIXME: is it OK to hard-code '.png' here?
name=$(printf "%s\n" "${file}" | cut -d/ -f2); # sloppy, sorry
mkdir -p "${TEMP}"/generated/${name};
make_real ${x}x${y} "${file}" "${TEMP}"/generated/${name}/${x}x${y}.png;
done
done
#---------------------------------------------------------------
# output: scale all wallpapers
#---------------------------------------------------------------
##
# For each input image, generate a full set of output images.
#
# Note that this loop includes all columns; rely on 'size_only'
# to handle the rest.
#
printf "%s\n" "${MAKE}" | while read k; do
size_only "${TEMP}"/generated ${k};
done
#---------------------------------------------------------------
# output: screenshots
#---------------------------------------------------------------
find "${TEMP}"/generated -mindepth 1 -maxdepth 1 -type d | sort | while read k; do
name=$(printf "%s\n" "${k}" | cut -d/ -f3); # sloppy, sorry
printf "Generating screenshot ('%s')...\n" "${KEEP}/${name}/screenshot.jpg";
gm convert "${k}"/1600x1000.png -resize 400x250^ "${KEEP}"/${name}/screenshot.jpg 2>/dev/null;
done
#---------------------------------------------------------------
# output: metadata
#---------------------------------------------------------------
##
# FIXME: make this not ugly
#
temp=$(mktemp);
cat >> "${temp}" <<"EOF"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE wallpapers SYSTEM "gnome-wp-list.dtd">
<wallpapers>
EOF
find "${TEMP}"/generated -mindepth 1 -maxdepth 1 -type d | sort | while read k; do
name=$(printf "%s\n" "${k}" | cut -d/ -f3); # sloppy, sorry
# fix structure
mv "${KEEP}"/${name} "${KEEP}"/${name}.tmp;
mkdir -p "${KEEP}"/${name}/contents;
mv "${KEEP}"/${name}.tmp "${KEEP}"/${name}/contents/images;
# compute metadata
case "${name}" in
background)
description="Default Background";
author_name="Adélie Platform Team";
;;
lockscreen)
description="Default Lockscreen";
author_name="Adélie Platform Team";
;;
*)
. "${IMGS}"/${name}/MANIFEST;
;;
esac
# write metadata to 'manifest.desktop'
# FIXME: we can do better than 'tr' below, but also what are
# the actual requirements? I'm just emulating what exists...
cat > "${KEEP}"/${name}/metadata.desktop <<EOF
[Desktop Entry]
Name=${description}
X-KDE-PluginInfo-Name=$(printf "%s\n" "${description}" | tr ' ' '-')
X-KDE-PluginInfo-Author=${author_name}
X-KDE-PluginInfo-License=CC-BY-SA-4.0
EOF
# write metadata to 'gnome-background-properties/Adelie.xml'
find "${KEEP}"/${name}/contents/images -type f \
| grep -v screenshot \
| sort | while read file; do
cat >> "${temp}" <<EOF
<wallpaper deleted="false">
<name>${description}</name>
<filename>/usr/share/wallpapers/${name}/contents/images/${file##*/}</filename>
<options>zoom</options>
</wallpaper>
EOF
done
done
##
# FIXME: make this not ugly
#
cat >> "${temp}" <<EOF
</wallpapers>
EOF
#---------------------------------------------------------------
# output: create tarball
#---------------------------------------------------------------
rm -fr adelie-wallpapers-${VTAG};
mkdir -p adelie-wallpapers-${VTAG}/usr/share;
# wallpapers
mv "${KEEP}" adelie-wallpapers-${VTAG}/usr/share/wallpapers;
# gnome-background-properties
mkdir -p adelie-wallpapers-${VTAG}/usr/share/gnome-background-properties;
mv "${temp}" adelie-wallpapers-${VTAG}/usr/share/gnome-background-properties/Adelie.xml;
# generate tarball
rm -f adelie-wallpapers-${VTAG}.tar.xz;
tar -pcJf adelie-wallpapers-${VTAG}.tar.xz adelie-wallpapers-${VTAG};
# clean up
rm -fr "${TEMP}"/generated;
rm -fr adelie-wallpapers-${VTAG};
|