Update icoconvert to use pathclass, globs, and auto-sort images.

This commit is contained in:
voussoir 2026-08-30 12:20:58 -07:00
parent d61bc3da25
commit 3f4476113f

View file

@ -92,6 +92,7 @@ import sys
from voussoirkit import betterhelp from voussoirkit import betterhelp
from voussoirkit import imagetools from voussoirkit import imagetools
from voussoirkit import pathclass
from voussoirkit import pipeable from voussoirkit import pipeable
from voussoirkit import vlogging from voussoirkit import vlogging
@ -127,9 +128,11 @@ def chunk_sequence(sequence, chunk_length, allow_incomplete=True):
def little(x, length): def little(x, length):
return x.to_bytes(length, byteorder='little') return x.to_bytes(length, byteorder='little')
def load_image(filename): def load_image(file):
image = PIL.Image.open(filename) image = PIL.Image.open(file.absolute_path)
(w, h) = image.size (w, h) = image.size
if w > 256 or h > 256:
log.info(f'{file.basename} is being downsampled to 256x256.')
(new_w, new_h) = imagetools.fit_into_bounds(w, h, 256, 256, only_shrink=True) (new_w, new_h) = imagetools.fit_into_bounds(w, h, 256, 256, only_shrink=True)
image = image.resize((new_w, new_h), resample=PIL.Image.LANCZOS) image = image.resize((new_w, new_h), resample=PIL.Image.LANCZOS)
image = image.convert('RGBA') image = image.convert('RGBA')
@ -205,7 +208,7 @@ def build_image_data_blob(image):
def images_to_ico(images): def images_to_ico(images):
# For some reason Windows reads the icons in reverse order. # For some reason Windows reads the icons in reverse order.
images.reverse() images.sort(key=lambda i: i.size[0] * i.size[1], reverse=True)
# The directory entries need to know their image's address, so therefore # The directory entries need to know their image's address, so therefore
# we must know the lengths of all the image binaries before we can write # we must know the lengths of all the image binaries before we can write
@ -237,16 +240,22 @@ def images_to_ico(images):
return final_data return final_data
def icoconvert_argparse(args): def icoconvert_argparse(args):
log.info('Iconifying %s', args.files) files = list(pathclass.glob_many_files(args.patterns))
images = [load_image(filename) for filename in args.files] if len(files) == 0:
raise ValueError('Got no input files.')
final_data = images_to_ico(images) log.info('Iconifying %s', [f.basename for f in files])
images = [load_image(file) for file in files]
iconame = os.path.splitext(args.files[0])[0] + '.ico' if args.output:
output_file = open(iconame, 'wb') icofile = pathclass.Path(args.output)
output_file.write(final_data) else:
output_file.close() icofile = files[0].replace_extension('ico')
pipeable.stderr(iconame)
ico_bytes = images_to_ico(images)
icofile.write('wb', ico_bytes)
pipeable.stderr(icofile.absolute_path)
return 0 return 0
@vlogging.main_decorator @vlogging.main_decorator
@ -257,12 +266,19 @@ def main(argv):
''', ''',
) )
parser.add_argument( parser.add_argument(
'files', 'patterns',
nargs='+', nargs='+',
help=''' help='''
One or more image files to put into the ico. One or more image files to put into the ico.
''', ''',
) )
parser.add_argument(
'--output',
dest='output',
nargs='?',
help='''
''',
)
parser.set_defaults(func=icoconvert_argparse) parser.set_defaults(func=icoconvert_argparse)
return betterhelp.go(parser, argv) return betterhelp.go(parser, argv)