#!/usr/bin/env bash # __ __ __ # .----.--| | .-----.----.----.|__|.-----.| |_ # | __| _ | |__ --| __| _|| || _ || _| # |____|_____| |_____|____|__| |__|| __||____| # |__| # # script to make cd jewel case inserts easily # by sun https://sx7n8.tech/ # # dependencies are: imagemagick, bash, awk # TODO: # - !!! Add support for back insert !!! # - Remove bugs # - Add more paper types DONE # - Make DPI a command line option DONE # - Add different folding points for inserts # - Clean up code and add more comments # - Improve input and output further DONE # usage message USAGE="Usage: $0 -p -c -b [-i ] [-m ] -o " # help message HELP="Script to create printable CD jewel case inserts Usage: $0 -p -c -b [-i ] [-m ] [-d DPI] -o Required options: -p Paper format a4 | letter | legal -c Album cover path Path to cover image -b Back type no | image -o Output file Path to save the resulting insert (NO PNG) Optional options: -i Back image path Required if back type is 'image' -m Border width (px) Adds a border around the cover/back -d DPI Desired DPI of the output DO NOT USE PNG FOR OUTPUT " # default DPI DPI="300" # error function error() { echo -e "Error: $1" >&2 echo -e "$USAGE" >&2 exit 1 } # file existance check check_file_exists() { if [ ! -f "$1" ]; then error "File '$1' does not exist." fi } # file existance check but opposite check_output_file() { if [ -f "$1" ]; then error "Output file '$1' already exists." fi } # number check check_dpi() { if ! [[ "$var" =~ ^[1-9][0-9]*$ ]]; then error "DPI is not a valid number" fi } # getops argument handling while getopts "hp:c:b:i:m:o:d:" o; do case "${o}" in h) echo -e "$HELP" exit ;; p) if [[ "$OPTARG" != "a4" && "$OPTARG" != "letter" ]]; then error "Invalid paper type '$OPTARG'. Must be 'a4' or 'letter'." fi PAPER="$OPTARG" ;; c) check_file_exists "$OPTARG" COVER="$OPTARG" COVERSIZE="$(identify -format "%w" "$COVER")" ;; b) if [[ "$OPTARG" != "no" && "$OPTARG" != "image" ]]; then error "Invalid back type '$OPTARG'. Must be 'no' or 'image'." fi BACKTYPE="$OPTARG" ;; i) if [[ "$BACKTYPE" != "image" ]]; then error "-i option requires back type to be 'image'." fi check_file_exists "$OPTARG" BACKIMG="$OPTARG" ;; m) BORDER="TRUE" BORDER_WIDTH="$OPTARG" ;; o) check_output_file "$OPTARG" OUTPUT="$OPTARG" ;; d) check_dpi "$OPTARG" DPI="$OPTARG" ;; *) echo -e "$USAGE" exit 1 ;; esac done # check if something is missing [[ -z "$PAPER" ]] && error "Missing paper format (-p)." [[ -z "$COVER" ]] && error "Missing cover image (-c)." [[ -z "$BACKTYPE" ]] && error "Missing back type (-b)." [[ -z "$OUTPUT" ]] && error "Missing output file (-o)." [[ "$BACKTYPE" == "image" && -z "$BACKIMG" ]] && error "Missing back image (-i) for back type 'image'." # function to convert mm to px with dpi CONVERT() { awk -v mm="$1" -v dpi="$2" 'BEGIN{printf("%d", mm/25.4*dpi + 0.5)}'; } # cover art size (mm) CO_MM="120" CO_PX="$(CONVERT "$CO_MM" "$DPI")" # Width and Height of paper in mm A4MM_W="210" A4MM_H="297" LTMM_W="216" LTMM_H="279" LGMM_W="216" LGMM_H="279" # same values in pixels A4PX="$(CONVERT "$A4MM_W" "$DPI")x$(CONVERT "$A4MM_H" "$DPI")" LTPX="$(CONVERT "$LTMM_W" "$DPI")x$(CONVERT "$LTMM_H" "$DPI")" LGPX="$(CONVERT "$LGMM_W" "$DPI")x$(CONVERT "$LGMM_H" "$DPI")" # assign to the 'size' variable the right value if [ "$PAPER" = "a4" ]; then SIZE=$A4PX elif [ "$PAPER" = "letter" ]; then SIZE=$LTPX elif [ "$PAPER" = "legal" ]; then SIZE=$LGPX fi # create a blank file with the specified paper type magick -colorspace sRGB -type TrueColor -depth 8 -size $SIZE canvas:white "$OUTPUT" > /dev/null # draws border (rectangle) if [ "$BORDER" = "TRUE" ]; then INSET=$((BORDER_WIDTH / 2)) magick ""$OUTPUT"" \( -size $((CO_PX + 2 * BORDER_WIDTH))x$((CO_PX * 2 + 2 * BORDER_WIDTH)) xc:none -colorspace sRGB -type TrueColor -depth 8 -fill none -stroke black -strokewidth $BORDER_WIDTH -draw "rectangle $INSET,$INSET $((CO_PX + BORDER_WIDTH - 1)),$((CO_PX * 2 + BORDER_WIDTH - 1))" \) -gravity center -composite ""$OUTPUT"" fi # adds the cover magick \ -colorspace sRGB\ -type TrueColor \ -depth 8 \ "$OUTPUT" \ \( "$COVER" \ -resize ${CO_PX}x${CO_PX} \ -rotate 270 \) \ -gravity center \ -geometry +0-$((CO_PX/2)) \ -composite \ "$OUTPUT" \ > /dev/null # adds back if [ "$BACKTYPE" = "image" ]; then # if the back is an image # adds image magick \ -colorspace sRGB \ -type TrueColor \ -depth 8 \ "$OUTPUT" \ \( "$BACKIMG" \ -resize ${CO_PX}x${CO_PX} \ -rotate 270 \) \ -gravity center \ -geometry +0+$((CO_PX/2)) \ -composite \ "$OUTPUT" \ > /dev/null else # if the back is not an image # adds white square magick \ -colorspace sRGB \ -type TrueColor \ -depth 8 \ "$OUTPUT" \ \( -size ${CO_PX}x${CO_PX} \ xc:'#FFFFFF' \) \ -gravity center \ -geometry +0+$((CO_PX/2)) \ -composite "$OUTPUT"\ > /dev/null fi