summaryrefslogblamecommitdiff
path: root/prepare
blob: f6b29d02d7078f0d286fbdf4fef40f5c66a9d70f (plain) (tree)
1
2
3
4
5
6
7
8






                                                                 
                     
















                                                                
 














































































                                                                
        

                    



                   



   





                                   










                                                                
                    











                                                                



















                                                                      
  
 


























































                                                                


















                                                                                   
                     
                                                                                                                             








                                                                


                         
























                                                                








                                                                

  
                                                                







                                         
                                                 

                                                            

                                                   

                                              




                                      






                                                             
                  

                            

                              


                   







                                                             
                  

                            

                               


                   


                                      
                



                   











                                                                
                             
                                            
                         
                             

                                                      
                          
         
 
                             
                                            
                         
                             


                                                      



















                                                                
                                                                












































                                                                                










                                                                                                  







                                                                





























                                                                                  
                                                  







                                                                    
                                                    

                                    





















                                                                                  
                                 









                                                                                        
                                       



                                                                     
                                 
#!/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};