add CLI to update icns files inplace

This commit is contained in:
relikd
2021-10-12 23:47:03 +02:00
parent 1ffc5c4851
commit 92775e7f8e
3 changed files with 70 additions and 7 deletions

View File

@@ -21,6 +21,7 @@ positional arguments:
command
extract (e) Read and extract contents of icns file(s).
compose (c) Create new icns file from provided image files.
update (u) Update existing icns file by inserting or removing media entries.
print (p) Print contents of icns file(s).
test (t) Test if icns file is valid.
convert (img) Convert images between PNG, ARGB, or RGB + alpha mask.
@@ -31,16 +32,21 @@ positional arguments:
```sh
# extract
icnsutil e ExistingIcon.icns -o ./outdir/
icnsutil e Existing.icns -o ./outdir/
# compose
icnsutil c NewIcon.icns 16x16.png 16x16@2x.png *.jp2
icnsutil c New.icns 16x16.png 16x16@2x.png *.jp2
# update
icnsutil u Existing.icns -rm toc ic04 ic05
icnsutil u Existing.icns -set is32=16.rgb dark="dark icon.icns"
icnsutil u Existing.icns -rm dark -set ic04=16.argb -o Updated.icns
# print
icnsutil p ExistingIcon.icns
icnsutil p Existing.icns
# verify valid format
icnsutil t ExistingIcon.icns
icnsutil t Existing.icns
# convert image
icnsutil img 1024.png 512@2x.jp2
@@ -57,7 +63,7 @@ icnsutil img png 16.rgb 16.mask
import icnsutil
# extract
img = icnsutil.IcnsFile('ExistingIcon.icns')
img = icnsutil.IcnsFile('Existing.icns')
img.export(out_dir, allowed_ext='png',
recursive=True, convert_png=True)
@@ -65,7 +71,14 @@ img.export(out_dir, allowed_ext='png',
img = icnsutil.IcnsFile()
img.add_media(file='16x16.png')
img.add_media(file='16x16@2x.png')
img.write('./new-icon.icns', toc=False)
img.write('./new-icon.icns')
# update
img = icnsutil.IcnsFile('Existing.icns')
img.add_media('icp4', file='16x16.png', force=True)
if img.remove_media('TOC '):
print('table of contents removed')
img.write('Existing.icns', toc=False)
# print
icnsutil.IcnsFile.description(fname, indent=2)

View File

@@ -213,6 +213,16 @@ def get(key: Media.KeyT) -> Media:
raise NotImplementedError('Unsupported icns type "' + str(key) + '"')
def key_from_readable(key: str) -> Media.KeyT:
key_mapping = {
'dark': b'\xFD\xD9\x2F\xA8',
'selected': 'slct',
'template': 'sbtp',
'toc': 'TOC ',
} # type: Dict[str, Media.KeyT]
return key_mapping.get(key.lower(), key)
def match_maxsize(total: int, typ: str) -> Media:
assert(typ == 'argb' or typ == 'rgb')
ret = [x for x in _TYPES.values() if x.is_type(typ) and x.maxsize == total]

View File

@@ -9,7 +9,7 @@ from argparse import ArgumentParser, ArgumentTypeError, RawTextHelpFormatter
from argparse import Namespace as ArgParams
if __name__ == '__main__':
sys.path[0] = os.path.dirname(sys.path[0])
from icnsutil import __version__, IcnsFile, ArgbImage
from icnsutil import __version__, IcnsFile, IcnsType, ArgbImage
def cli_extract(args: ArgParams) -> None:
@@ -44,6 +44,33 @@ def cli_compose(args: ArgParams) -> None:
img.write(dest, toc=not args.no_toc)
def cli_update(args: ArgParams) -> None:
''' Update existing icns file by inserting or removing media entries. '''
icns = IcnsFile(args.file)
has_changes = False
# remove media
for x in args.rm or []:
has_changes |= icns.remove_media(IcnsType.key_from_readable(x))
# add media
for key_val in args.set or []:
def fail():
raise ArgumentTypeError(
'Expected arg format KEY=FILE - got "{}"'.format(key_val))
if '=' not in key_val:
fail()
key, val = key_val.split('=', )
if not val:
fail()
if not os.path.isfile(val):
raise ArgumentTypeError('File does not exist "{}"'.format(val))
icns.add_media(IcnsType.key_from_readable(key), file=val, force=True)
has_changes = True
# write file
if has_changes or args.o:
icns.write(args.o or args.file, toc=icns.has_toc())
def cli_print(args: ArgParams) -> None:
''' Print contents of icns file(s). '''
for fname in enum_with_stdin(args.file):
@@ -171,6 +198,19 @@ Notes:
template, selected, dark
'''
# Update
cmd = add_command('update', 'u', cli_update)
cmd.add_argument('file', type=PathExist('f', stdin=True),
metavar='FILE', help='The icns file to be updated.')
cmd.add_argument('-o', '--output', type=str, metavar='OUT_FILE',
help='Choose another destination, dont overwrite input.')
grp = cmd.add_argument_group('action')
grp.add_argument('-rm', type=str, nargs='+', metavar='KEY',
help='Remove media keys from icns file')
grp.add_argument('-set', type=str, nargs='+', metavar='KEY=FILE',
help='Append or replace media in icns file')
cmd.epilog = 'KEY supports names like "dark", "selected", and "template"'
# Print
cmd = add_command('print', 'p', cli_print)
cmd.add_argument('-v', '--verbose', action='store_true',