add CLI to update icns files inplace
This commit is contained in:
25
README.md
25
README.md
@@ -21,6 +21,7 @@ positional arguments:
|
|||||||
command
|
command
|
||||||
extract (e) Read and extract contents of icns file(s).
|
extract (e) Read and extract contents of icns file(s).
|
||||||
compose (c) Create new icns file from provided image files.
|
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).
|
print (p) Print contents of icns file(s).
|
||||||
test (t) Test if icns file is valid.
|
test (t) Test if icns file is valid.
|
||||||
convert (img) Convert images between PNG, ARGB, or RGB + alpha mask.
|
convert (img) Convert images between PNG, ARGB, or RGB + alpha mask.
|
||||||
@@ -31,16 +32,21 @@ positional arguments:
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
# extract
|
# extract
|
||||||
icnsutil e ExistingIcon.icns -o ./outdir/
|
icnsutil e Existing.icns -o ./outdir/
|
||||||
|
|
||||||
# compose
|
# 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
|
# print
|
||||||
icnsutil p ExistingIcon.icns
|
icnsutil p Existing.icns
|
||||||
|
|
||||||
# verify valid format
|
# verify valid format
|
||||||
icnsutil t ExistingIcon.icns
|
icnsutil t Existing.icns
|
||||||
|
|
||||||
# convert image
|
# convert image
|
||||||
icnsutil img 1024.png 512@2x.jp2
|
icnsutil img 1024.png 512@2x.jp2
|
||||||
@@ -57,7 +63,7 @@ icnsutil img png 16.rgb 16.mask
|
|||||||
import icnsutil
|
import icnsutil
|
||||||
|
|
||||||
# extract
|
# extract
|
||||||
img = icnsutil.IcnsFile('ExistingIcon.icns')
|
img = icnsutil.IcnsFile('Existing.icns')
|
||||||
img.export(out_dir, allowed_ext='png',
|
img.export(out_dir, allowed_ext='png',
|
||||||
recursive=True, convert_png=True)
|
recursive=True, convert_png=True)
|
||||||
|
|
||||||
@@ -65,7 +71,14 @@ img.export(out_dir, allowed_ext='png',
|
|||||||
img = icnsutil.IcnsFile()
|
img = icnsutil.IcnsFile()
|
||||||
img.add_media(file='16x16.png')
|
img.add_media(file='16x16.png')
|
||||||
img.add_media(file='16x16@2x.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
|
# print
|
||||||
icnsutil.IcnsFile.description(fname, indent=2)
|
icnsutil.IcnsFile.description(fname, indent=2)
|
||||||
|
|||||||
@@ -213,6 +213,16 @@ def get(key: Media.KeyT) -> Media:
|
|||||||
raise NotImplementedError('Unsupported icns type "' + str(key) + '"')
|
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:
|
def match_maxsize(total: int, typ: str) -> Media:
|
||||||
assert(typ == 'argb' or typ == 'rgb')
|
assert(typ == 'argb' or typ == 'rgb')
|
||||||
ret = [x for x in _TYPES.values() if x.is_type(typ) and x.maxsize == total]
|
ret = [x for x in _TYPES.values() if x.is_type(typ) and x.maxsize == total]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from argparse import ArgumentParser, ArgumentTypeError, RawTextHelpFormatter
|
|||||||
from argparse import Namespace as ArgParams
|
from argparse import Namespace as ArgParams
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sys.path[0] = os.path.dirname(sys.path[0])
|
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:
|
def cli_extract(args: ArgParams) -> None:
|
||||||
@@ -44,6 +44,33 @@ def cli_compose(args: ArgParams) -> None:
|
|||||||
img.write(dest, toc=not args.no_toc)
|
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:
|
def cli_print(args: ArgParams) -> None:
|
||||||
''' Print contents of icns file(s). '''
|
''' Print contents of icns file(s). '''
|
||||||
for fname in enum_with_stdin(args.file):
|
for fname in enum_with_stdin(args.file):
|
||||||
@@ -171,6 +198,19 @@ Notes:
|
|||||||
template, selected, dark
|
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
|
# Print
|
||||||
cmd = add_command('print', 'p', cli_print)
|
cmd = add_command('print', 'p', cli_print)
|
||||||
cmd.add_argument('-v', '--verbose', action='store_true',
|
cmd.add_argument('-v', '--verbose', action='store_true',
|
||||||
|
|||||||
Reference in New Issue
Block a user