Skip to content

Backfill icons from provided images #386

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
freakboy3742 opened this issue Apr 29, 2020 · 4 comments
Open

Backfill icons from provided images #386

freakboy3742 opened this issue Apr 29, 2020 · 4 comments
Labels
enhancement New features, or improvements to existing features.

Comments

@freakboy3742
Copy link
Member

Briefcase currently requires that the user provide icons of in various formats. However, if you have a high-res PNG format, any other format can be generated by image conversion.

Briefcase should try to use a correctly named file in the right size and format if it's available; but if it isn't, it should try to backfill by converting the high-res PNG to the needed size and format. This should be clearly logged so the end user knows what has happened.

Pillow can be used for most of these operations, but Pillow doesn't currently support ICNS; however, macOS ships with a tool to generate ICNS files from PNGs.

Creating an ICNS file:

Into a directory named myicon.iconset, put files with the following names and sizes:

  • icon_512x512@2x.png
  • icon_512x512.png
  • icon_256x256@2x.png
  • icon_256x256.png
  • icon_128x128@2x.png
  • icon_128x128.png
  • icon_32x32@2x.png
  • icon_32x32.png
  • icon_16x16@2x.png
  • icon_16x16.png

A 16x16@2x icon is 32x32 pixels; so yes - you need to have 2 copies of the same 32x32 icon (if you're paying close attention to the details you can specify a different icon; however, if you're autoscaling from other sizes, you're not paying that sort of attention).

Then, invoke: iconutil -c icns myicon.iconset. This will produce myicon.icns.

@freakboy3742 freakboy3742 added enhancement New features, or improvements to existing features. up-for-grabs labels Apr 29, 2020
@Andrei-Pozolotin
Copy link

pillow now knows about iconutil

https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#icns

https://github.com/python-pillow/Pillow/blob/master/src/PIL/IcnsImagePlugin.py#L306

def _save(im, fp, filename):
    """
    Saves the image as a series of PNG files,
    that are then converted to a .icns file
    using the macOS command line utility 'iconutil'.
    macOS only.
    """

@Andrei-Pozolotin
Copy link

and linux has png2icns / icns2png

https://icns.sourceforge.io/

https://archlinux.org/packages/community/x86_64/libicns/

usr/
usr/bin/
usr/bin/icns2png
usr/bin/icontainer2icns
usr/bin/png2icns
usr/include/
usr/include/icns.h
usr/lib/
usr/lib/libicns.so
usr/lib/libicns.so.1
usr/lib/libicns.so.1.2.0
usr/lib/pkgconfig/
usr/lib/pkgconfig/libicns.pc
usr/share/
usr/share/man/
usr/share/man/man1/
usr/share/man/man1/icns2png.1.gz
usr/share/man/man1/icontainer2icns.1.gz
usr/share/man/man1/png2icns.1.gz

@Andrei-Pozolotin
Copy link

an easy solution could be to include into the default app template
a linux script which produces images for all platforms, for example:

#!/usr/bin/env bash

set -e -u

image_source=${1:-arkon.png}
image_target=${2:-tasker}
image_folder=${3:-.}

echo "### master image: $image_source"
echo "### image prefix: $image_target"
echo "### image folder: $image_folder"

# 
hash convert ||  { echo "missing imagemagick/convert" ; exit 1 ; }
hash png2icns ||  { echo "missing libicns/png2icns" ; exit 1 ; }
[ -f ${image_source} ] ||  { echo "missing image_source: ${image_source}" ; exit 1 ; }

[ -d ${image_folder} ] || mkdir -p ${image_folder}

#
proper_spec_list=(
   "24x1" "48x1" "64x1" "96x1" "128x1"
   "20x1" "20x2" "20x3"
   "29x1" "29x2" "29x3"
   "40x1" "40x2" "40x3"
   "60x2" "60x3"
   "76x1" "76x2"
   "83.5x2" "1024x1"
)

convert_proper() {
    for image_spec in ${proper_spec_list[*]} ; do
       size=${image_spec%x*}
       scale=${image_spec##*x}
       resize=$(bc <<< ${size}*${scale} )
       echo "### apply ${image_source} spec: ${size}x${size}@${scale}"
       convert ${image_source} \
          -resize ${resize}x${resize} \
          -unsharp '1.5x1+0.7+0.02' \
          ${image_folder}/${image_target}-${size}x${size}@${scale}x.png
    done
}


android_spec_list=(
    48 72 96 144 192
)

convert_android() {
    convert_android_round
    convert_android_square
}

convert_android_round() {
    file_type="round"
    for image_spec in ${android_spec_list[*]} ; do
       size=${image_spec}
       scale=1
       resize=$(bc <<< ${size}*${scale} )
       corner=$(bc <<< ${size}*0.5 ) # 50%
       file_name="${image_target}-${file_type}-${size}.png"
       file_path="${image_folder}/${file_name}"
       mask_path="${image_folder}/round-mask.png"
       echo "### apply/android spec: ${size}x${size}@${scale} file: $file_name"
       # produce mask
       convert -size ${resize}x${resize} xc:none \
          -draw "roundrectangle 0,0,${resize},${resize},${corner},${corner}" \
          ${mask_path}
       # produce resize
       convert ${image_source} \
          -resize ${resize}x${resize} \
          -unsharp '1.5x1+0.7+0.02' \
          ${file_path}
       # produce composite
       convert ${file_path} \
          -matte ${mask_path} \
          -compose DstIn -composite \
          ${file_path}
       # destroy mask
       rm ${mask_path}
    done
}

convert_android_square() {
    file_type="square"
    for image_spec in ${android_spec_list[*]} ; do
       size=${image_spec}
       scale=1
       resize=$(bc <<< ${size}*${scale} )
       file_name="${image_target}-${file_type}-${size}.png"
       file_path="${image_folder}/${file_name}"
       echo "### apply/android spec: ${size}x${size}@${scale} file: $file_name"
       convert ${image_source} \
          -resize ${resize}x${resize} \
          -unsharp '1.5x1+0.7+0.02' \
          ${file_path}
    done
}


ios_spec_list=(
    20 29 40 58 60 76 80 87 120 152 167 180 1024
)

convert_ios() {
    for image_spec in ${ios_spec_list[*]} ; do
       size=${image_spec}
       scale=1
       resize=$(bc <<< ${size}*${scale} )
       file_name="${image_target}-${size}.png"
       file_path="${image_folder}/${file_name}"
       echo "### apply/ios spec: ${size}x${size}@${scale} file: $file_name"
       convert ${image_source} \
          -resize ${resize}x${resize} \
          -unsharp '1.5x1+0.7+0.02' \
          ${file_path}
    done
}


macos_spec_list=(
    16 32 48 128 256 512
)

convert_macos() {
    file_list=""
    for image_spec in ${macos_spec_list[*]} ; do
       size=${image_spec}
       scale=1
       resize=$(bc <<< ${size}*${scale} )
       file_name="${image_target}-${size}.png"
       file_path="${image_folder}/${file_name}"
       echo "### apply/macos spec: ${size}x${size}@${scale} file: $file_name"
       convert ${image_source} \
          -resize ${resize}x${resize} \
          -unsharp '1.5x1+0.7+0.02' \
          ${file_path}
       file_list="${file_list} ${file_path}"
    done
    png2icns "${image_target}.icns" ${file_list[@]}
}


windows_spec_list="16,24,32,48,64,72,96,128,256"

convert_windows() {
    echo "### apply/windows spec: ${windows_spec_list}"
    convert ${image_source} \
        -background transparent \
        -define icon:auto-resize=${windows_spec_list} \
        "${image_folder}/${image_target}.ico"
}

convert_default() {
    size="256"
    echo "### apply/default size: ${size}"
    src="${image_target}-256.png"
    dst="${image_target}.png"
    cp ${src} ${dst}  
}


convert_android

convert_ios

convert_macos

convert_windows

convert_default

@eltoro0815
Copy link

eltoro0815 commented Jun 5, 2024

The actual beeware version expects different files. I added some some lines of code. Feel free to remove stuff which is no longer needed ;)

To update the icons for your android app, you have to:

briefcase create android
briefcase build android
briefcase run android
#!/usr/bin/env bash

set -e -u

image_source=${1:-thor_edit.png}
image_target=${2:-daciaspringstatus}
image_folder=${3:-.}

echo "### master image: $image_source"
echo "### image prefix: $image_target"
echo "### image folder: $image_folder"

#
hash convert ||  { echo "missing imagemagick/convert" ; exit 1 ; }
hash png2icns ||  { echo "missing libicns/png2icns" ; exit 1 ; }
[ -f ${image_source} ] ||  { echo "missing image_source: ${image_source}" ; exit 1 ; }

[ -d ${image_folder} ] || mkdir -p ${image_folder}

#
proper_spec_list=(
   "24x1" "48x1" "64x1" "96x1" "128x1"
   "20x1" "20x2" "20x3"
   "29x1" "29x2" "29x3"
   "40x1" "40x2" "40x3"
   "60x2" "60x3"
   "76x1" "76x2"
   "83.5x2" "1024x1"
)

convert_proper() {
    for image_spec in ${proper_spec_list[*]} ; do
       size=${image_spec%x*}
       scale=${image_spec##*x}
       resize=$(bc <<< ${size}*${scale} )
       echo "### apply ${image_source} spec: ${size}x${size}@${scale}"
       convert ${image_source} \
          -resize ${resize}x${resize} \
          -unsharp '1.5x1+0.7+0.02' \
          ${image_folder}/${image_target}-${size}x${size}@${scale}x.png
    done
}


android_spec_list=(
    48 72 96 144 192 320 480 640 960 1280
)

convert_android() {
    convert_android_round
    convert_android_square
}

convert_android_round() {
    file_type="round"
    for image_spec in ${android_spec_list[*]} ; do
       size=${image_spec}
       scale=1
       resize=$(bc <<< ${size}*${scale} )
       corner=$(bc <<< ${size}*0.5 ) # 50%
       file_name="${image_target}-${file_type}-${size}.png"
       file_path="${image_folder}/${file_name}"
       mask_path="${image_folder}/round-mask.png"
       echo "### apply/android spec: ${size}x${size}@${scale} file: $file_name"
       # produce mask
       convert -size ${resize}x${resize} xc:none \
          -draw "roundrectangle 0,0,${resize},${resize},${corner},${corner}" \
          ${mask_path}
       # produce resize
       convert ${image_source} \
          -resize ${resize}x${resize} \
          -unsharp '1.5x1+0.7+0.02' \
          ${file_path}
       # produce composite
       convert ${file_path} \
          -matte ${mask_path} \
          -compose DstIn -composite \
          ${file_path}
       # destroy mask
       rm ${mask_path}
    done
}

convert_android_square() {
    file_type="square"
    for image_spec in ${android_spec_list[*]} ; do
       size=${image_spec}
       scale=1
       resize=$(bc <<< ${size}*${scale} )
       file_name="${image_target}-${file_type}-${size}.png"
       file_path="${image_folder}/${file_name}"
       echo "### apply/android spec: ${size}x${size}@${scale} file: $file_name"
       convert ${image_source} \
          -resize ${resize}x${resize} \
          -unsharp '1.5x1+0.7+0.02' \
          ${file_path}
    done
}


ios_spec_list=(
    20 29 40 58 60 76 80 87 120 152 167 180 1024
)

convert_ios() {
    for image_spec in ${ios_spec_list[*]} ; do
       size=${image_spec}
       scale=1
       resize=$(bc <<< ${size}*${scale} )
       file_name="${image_target}-${size}.png"
       file_path="${image_folder}/${file_name}"
       echo "### apply/ios spec: ${size}x${size}@${scale} file: $file_name"
       convert ${image_source} \
          -resize ${resize}x${resize} \
          -unsharp '1.5x1+0.7+0.02' \
          ${file_path}
    done
}


macos_spec_list=(
    16 32 48 128 256 512
)

convert_macos() {
    file_list=""
    for image_spec in ${macos_spec_list[*]} ; do
       size=${image_spec}
       scale=1
       resize=$(bc <<< ${size}*${scale} )
       file_name="${image_target}-${size}.png"
       file_path="${image_folder}/${file_name}"
       echo "### apply/macos spec: ${size}x${size}@${scale} file: $file_name"
       convert ${image_source} \
          -resize ${resize}x${resize} \
          -unsharp '1.5x1+0.7+0.02' \
          ${file_path}
       file_list="${file_list} ${file_path}"
    done
    png2icns "${image_target}.icns" ${file_list[@]}
}


windows_spec_list="16,24,32,48,64,72,96,128,256"

convert_windows() {
    echo "### apply/windows spec: ${windows_spec_list}"
    convert ${image_source} \
        -background transparent \
        -define icon:auto-resize=${windows_spec_list} \
        "${image_folder}/${image_target}.ico"
}



convert_default() {
    size="256"
    echo "### apply/default size: ${size}"
    src="${image_target}-256.png"
    dst="${image_target}.png"
    cp ${src} ${dst}
}

adaptive_spec_list=(
    108 162 216 324 432
)

convert_adaptive() {
    file_type="adaptive"
    for image_spec in ${adaptive_spec_list[*]} ; do
       size=${image_spec}
       scale=1
       resize=$(bc <<< ${size}*${scale} )
       file_name="${image_target}-${file_type}-${size}.png"
       file_path="${image_folder}/${file_name}"
       echo "### apply/adaptive spec: ${size}x${size}@${scale} file: $file_name"
       convert ${image_source} \
          -resize ${resize}x${resize} \
          -unsharp '1.5x1+0.7+0.02' \
          ${file_path}
    done
}



convert_android

convert_ios

convert_macos

convert_windows

convert_default

convert_adaptive

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New features, or improvements to existing features.
Projects
None yet
Development

No branches or pull requests

3 participants