proper module with setup.py

+ 2 bugfixes ("T" and channels)
This commit is contained in:
relikd
2021-09-28 21:14:54 +02:00
parent ae009d4925
commit 823ed3aaa9
12 changed files with 345 additions and 168 deletions

23
.gitignore vendored
View File

@@ -2,3 +2,26 @@
/*.txt
/tests/format-support-*/
/tests/fixtures/tmp_*
__pycache__/
*.py[cod]
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

View File

@@ -1,26 +1,44 @@
.PHONY: help test sys-icons-print sys-icons-test
.PHONY: help
help:
@echo 'Available commands: test, sys-icons-print, sys-icons-test'
@echo 'commands:'
@echo ' install, uninstall, test, dist, sys-icons-print, sys-icons-test'
.PHONY: install
install:
[ -z "$${VIRTUAL_ENV}" ] \
&& python3 -m pip install -e . --user \
|| python3 -m pip install -e .
.PHONY: uninstall
uninstall:
python3 -m pip uninstall icnsutil
rm -rf ./*.egg-info/
.PHONY: test
test:
python3 tests/test_icnsutil.py
_listofsystemicns.txt:
.PHONY: dist
dist:
@python3 setup.py sdist --formats=tar bdist_wheel \
|| echo '-> you can not do this inside a virtual environment.'
@echo
rm -rf ./*.egg-info/ ./build/ MANIFEST
_icns_list.txt:
@echo 'Generate list of system icns files...'
find /Applications -type f -name '*.icns' > _listofsystemicns.txt || echo
find /Users -type f -name '*.icns' >> _listofsystemicns.txt || echo
find /Library -type f -name '*.icns' >> _listofsystemicns.txt || echo
find /System -not \( -path '/System/Volumes' -prune \) \
-find /Applications -type f -name '*.icns' > _icns_list.txt
-find /Users -type f -name '*.icns' >> _icns_list.txt
-find /Library -type f -name '*.icns' >> _icns_list.txt
-find /System -not \( -path '/System/Volumes' -prune \) \
-not \( -path '/System/Library/Templates' -prune \) \
-type f -name '*.icns' >> _listofsystemicns.txt || echo 'Done.'
-type f -name '*.icns' >> _icns_list.txt
@echo 'Done.'
sys-icons-print: _listofsystemicns.txt
@while read fname; do \
./cli.py print "$${fname}"; \
done < _listofsystemicns.txt
.PHONY: sys-icons-print
sys-icons-print: _icns_list.txt
@cat _icns_list.txt | python3 -m icnsutil print -
sys-icons-test: _listofsystemicns.txt
@while read fname; do \
./cli.py test -q "$${fname}"; \
done < _listofsystemicns.txt
.PHONY: sys-icons-test
sys-icons-test: _icns_list.txt
@cat _icns_list.txt | python3 -m icnsutil test -q -

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env python3
import PackBytes # pack, unpack, msb_stream
import IcnsType # match_maxsize
from . import IcnsType, PackBytes
try:
from PIL import Image
PIL_ENABLED = True
@@ -108,6 +107,7 @@ class ArgbImage:
raise ImportError('Install Pillow to support PNG conversion.')
img = Image.open(fname, mode='r')
self.size = img.size
self.channels = 4
self.a = []
self.r = []
self.g = []

View File

@@ -1,10 +1,9 @@
#!/usr/bin/env python3
import os # path
import sys # stderr
import RawData
import IcnsType
import os # path, makedirs, remove
import struct # unpack float in _description()
from ArgbImage import ArgbImage # in _export_to_png()
from sys import stderr
from . import RawData, IcnsType
from .ArgbImage import ArgbImage
class IcnsFile:
@@ -49,7 +48,7 @@ class IcnsFile:
yield 'Invalid data length for {}: {} != {}'.format(
key, len(data), iType.maxsize)
# if file is not an icns file
except TypeError as e:
except RawData.ParserError as e:
yield e
return
@@ -86,30 +85,32 @@ class IcnsFile:
''' Expects an enumerator with (key, size, data) '''
txt = ''
offset = 8 # already with icns header
try:
for key, data in enumerator:
# actually, icns length should be -8 (artificially appended header)
size = len(data)
txt += ' ' * indent
txt += os.linesep + ' ' * indent
txt += '{}: {} bytes'.format(key, size)
if verbose:
txt += ', offset: {}'.format(offset)
offset += size + 8
if key == 'name':
txt += ', value: "{}"\n'.format(data.decode('utf-8'))
txt += ', value: "{}"'.format(data.decode('utf-8'))
continue
if key == 'icnV':
txt += ', value: {}\n'.format(struct.unpack('>f', data)[0])
txt += ', value: {}'.format(struct.unpack('>f', data)[0])
continue
ext = RawData.determine_file_ext(data)
try:
iType = IcnsType.get(key)
if not ext:
ext = iType.types[-1]
desc = iType.filename(size_only=True)
txt += ', {}: {}\n'.format(ext or 'binary', desc)
ext = iType.fallback_ext()
txt += ', ' + ext + ': ' + iType.filename(size_only=True)
except NotImplementedError:
txt += ': UNKNOWN TYPE: {}\n'.format(ext or data[:6])
return txt
txt += ': UNKNOWN TYPE: ' + str(ext or data[:6])
return txt[len(os.linesep):] + os.linesep
# if file is not an icns file
except RawData.ParserError as e:
return ' ' * indent + str(e) + os.linesep
def __init__(self, file=None):
''' Read .icns file and load bundled media files into memory. '''
@@ -123,7 +124,7 @@ class IcnsFile:
IcnsType.get(key)
except NotImplementedError:
print('Warning: unknown media type: {}, {} bytes, "{}"'.format(
key, len(data), file), file=sys.stderr)
key, len(data), file), file=stderr)
def add_media(self, key=None, *, file=None, data=None, force=False):
'''
@@ -272,7 +273,6 @@ class IcnsFile:
fname = iType.filename(key_only=key_suffix, size_only=True)
fname = os.path.join(outdir, fname + '.png')
if iType.bits == 1:
# return None
ArgbImage.from_mono(data, iType).write_png(fname)
else:
mask_data = self.media[mask_key] if mask_key else None
@@ -285,5 +285,5 @@ class IcnsFile:
type(self).__name__, self.infile, lst)
def __str__(self):
return 'File: ' + (self.infile or '-mem-') + '\n' \
return 'File: ' + (self.infile or '-mem-') + os.linesep \
+ IcnsFile._description(self.media.items(), indent=2)

View File

@@ -4,13 +4,17 @@ Namespace for the ICNS format.
@see https://en.wikipedia.org/wiki/Apple_Icon_Image_format
'''
import os # path
import RawData
import PackBytes
# import icnsutil # PackBytes, RawData
from . import PackBytes, RawData
class CanNotDetermine(Exception):
pass
class Media:
__slots__ = ['key', 'types', 'size', 'channels', 'bits', 'availability',
'desc', 'compressable', 'retina', 'maxsize']
'desc', 'compressable', 'retina', 'maxsize', 'ext_certain']
def __init__(self, key, types, size=None, *,
ch=None, bits=None, os=None, desc=''):
@@ -33,6 +37,8 @@ class Media:
self.maxsize = None
if size and ch and bits:
self.maxsize = self.size[0] * self.size[1] * ch * bits // 8
self.ext_certain = all(x in ['png', 'argb', 'plist', 'jp2', 'icns']
for x in self.types)
def is_type(self, typ):
return typ in self.types
@@ -40,6 +46,11 @@ class Media:
def is_binary(self) -> bool:
return any(x in self.types for x in ['rgb', 'bin'])
def fallback_ext(self):
if self.channels in [1, 2]:
return self.desc # guaranteed to be icon, mask, or iconmask
return self.types[-1]
def split_channels(self, uncompressed_data):
if self.channels not in [3, 4]:
raise NotImplementedError('Only RGB and ARGB data supported.')
@@ -108,7 +119,7 @@ class Media:
self.channels, self.bits, self.maxsize)
if self.desc:
T += self.desc + ', '
return '{}: {T}macOS {}+'.format(
return '{}: {}macOS {}+'.format(
self.key, T, self.availability or '?')
@@ -231,9 +242,11 @@ def guess(data, filename=None):
return _TYPES[bname]
ext = RawData.determine_file_ext(data)
if not ext and filename and filename.endswith('.rgb'):
ext = 'rgb'
# Guess by image size and retina flag
size = RawData.determine_image_size(data, ext) # None for non-image types
size = RawData.determine_image_size(data, ext) if ext else None
retina = bname.lower().endswith('@2x') if filename else False
# Icns specific names
desc = None
@@ -244,19 +257,22 @@ def guess(data, filename=None):
choices = []
for x in _TYPES.values():
if size != x.size: # currently no support for RGB and binary data
continue
if ext and not x.is_type(ext):
continue
if retina != x.retina: # png + jp2
continue
if ext:
if size != x.size or not x.is_type(ext):
continue
if desc and desc != x.desc: # icns only
continue
else: # not ext
if x.ext_certain:
continue
choices.append(x)
if len(choices) == 1:
return choices[0]
# Try get most favorable type (sort order of types)
if ext:
best_i = 99
best_choice = []
for x in choices:
@@ -269,6 +285,6 @@ def guess(data, filename=None):
if len(best_choice) == 1:
return best_choice[0]
# Else
raise ValueError('Could not determine type one of {} -- {}'.format(
[x.key for x in choices],
{'type': ext, 'size': size, 'retina': retina}))
raise CanNotDetermine(
'Could not determine type for file: "{}" one of {}.'.format(
filename, [x.key for x in choices]))

View File

@@ -1,7 +1,10 @@
#!/usr/bin/env python3
import struct # pack, unpack
import PackBytes # get_size
import IcnsType # get, match_maxsize
from . import IcnsType, PackBytes
class ParserError(Exception):
pass
def determine_file_ext(data):
@@ -34,6 +37,10 @@ def determine_image_size(data, ext=None):
elif ext == 'argb':
total = PackBytes.get_size(data[4:]) # without ARGB header
return IcnsType.match_maxsize(total, 'argb').size
elif ext == 'rgb':
if data[:4] == '\x00\x00\x00\x00':
data = data[4:] # without it32 header
return IcnsType.match_maxsize(PackBytes.get_size(data), 'rgb').size
elif ext == 'jp2':
if data[:4] == b'\xFF\x4F\xFF\x51':
return struct.unpack('>II', data[8:16])
@@ -91,13 +98,13 @@ def parse_icns_file(fname):
'''
Parse file and yield media entries: (key, data)
:raises:
TypeError: if file is not an icns file ("icns" header missing)
ParserError: if file is not an icns file ("icns" header missing)
'''
with open(fname, 'rb') as fp:
# Check whether it is an actual ICNS file
magic_num, _ = icns_header_read(fp.read(8)) # ignore total size
if magic_num != 'icns':
raise TypeError('Not an ICNS file, missing "icns" header.')
raise ParserError('Not an ICNS file, missing "icns" header.')
# Read media entries as long as there is something to read
while True:
key, size = icns_header_read(fp.read(8))

View File

@@ -4,14 +4,6 @@ A fully-featured python library to handle reading and writing icns files.
'''
__version__ = '1.0'
import sys
if __name__ != '__main__':
sys.path.insert(0, __path__[0])
# static modules
import IcnsType
import PackBytes
import RawData
# class modules
from ArgbImage import ArgbImage, PIL_ENABLED
from IcnsFile import IcnsFile
from .IcnsFile import IcnsFile
from .ArgbImage import ArgbImage, PIL_ENABLED
from . import IcnsType, PackBytes, RawData

3
icnsutil/__main__.py Normal file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env python3
from .cli import main
main()

View File

@@ -2,18 +2,18 @@
'''
Export existing icns files or compose new ones.
'''
import os # path, mkdir
import icnsutil
from sys import stderr
import os # path, makedirs
import sys # path, stderr
from argparse import ArgumentParser, ArgumentTypeError, RawTextHelpFormatter
__version__ = icnsutil.__version__
if __name__ == '__main__':
sys.path[0] = os.path.dirname(sys.path[0])
from icnsutil import __version__, IcnsFile
def cli_extract(args):
''' Read and extract contents of icns file(s). '''
multiple = len(args.file) > 1
for i, fname in enumerate(args.file):
multiple = len(args.file) > 1 or '-' in args.file
for i, fname in enumerate(enum_with_stdin(args.file)):
# PathExist ensures that all files and directories exist
out = args.export_dir
if out and multiple:
@@ -21,7 +21,7 @@ def cli_extract(args):
os.makedirs(out, exist_ok=True)
pred = 'png' if args.png_only else None
icnsutil.IcnsFile(fname).export(
IcnsFile(fname).export(
out, allowed_ext=pred, recursive=args.recursive,
convert_png=args.convert, key_suffix=args.keys)
@@ -34,30 +34,29 @@ def cli_compose(args):
if not args.force and os.path.exists(dest):
print(
'File "{}" already exists. Force overwrite with -f.'.format(dest),
file=stderr)
file=sys.stderr)
return 1
img = icnsutil.IcnsFile()
for x in args.source:
img = IcnsFile()
for x in enum_with_stdin(args.source):
img.add_media(file=x)
img.write(dest, toc=not args.no_toc)
def cli_print(args):
''' Print contents of icns file(s). '''
for fname in args.file:
for fname in enum_with_stdin(args.file):
print('File:', fname)
print(icnsutil.IcnsFile.description(
fname, verbose=args.verbose, indent=2))
print(IcnsFile.description(fname, verbose=args.verbose, indent=2))
def cli_verify(args):
''' Test if icns file is valid. '''
for fname in args.file:
for fname in enum_with_stdin(args.file):
is_valid = True
if not args.quiet:
print('File:', fname)
is_valid = None
for issue in icnsutil.IcnsFile.verify(fname):
for issue in IcnsFile.verify(fname):
if is_valid:
print('File:', fname)
is_valid = False
@@ -66,12 +65,24 @@ def cli_verify(args):
print('OK')
def enum_with_stdin(file_arg):
for x in file_arg:
if x == '-':
for line in sys.stdin.readlines():
yield line.strip()
else:
yield x
def main():
class PathExist:
def __init__(self, kind=None):
def __init__(self, kind=None, stdin=False):
self.kind = kind
self.stdin = stdin
def __call__(self, path):
if self.stdin and path == '-':
return '-'
if not os.path.exists(path) or \
self.kind == 'f' and not os.path.isfile(path) or \
self.kind == 'd' and not os.path.isdir(path):
@@ -81,7 +92,7 @@ def main():
# Args Parser
parser = ArgumentParser(description=__doc__,
formatter_class=RawTextHelpFormatter)
parser.set_defaults(func=lambda _: parser.print_help(stderr))
parser.set_defaults(func=lambda _: parser.print_help(sys.stderr))
parser.add_argument(
'-v', '--version', action='version', version='icnsutil ' + __version__)
sub_parser = parser.add_subparsers(metavar='command')
@@ -106,7 +117,7 @@ def main():
'--png-only', action='store_true',
help='do not extract ARGB, binary, and meta files')
cmd.add_argument(
'file', nargs='+', type=PathExist('f'), metavar='FILE',
'file', nargs='+', type=PathExist('f', stdin=True), metavar='FILE',
help='One or more .icns files.')
cmd.set_defaults(func=cli_extract)
@@ -124,7 +135,7 @@ def main():
'target', type=str, metavar='destination',
help='Output file for newly created icns file.')
cmd.add_argument(
'source', nargs='+', type=PathExist('f'), metavar='src',
'source', nargs='+', type=PathExist('f', stdin=True), metavar='src',
help='One or more media files: png, argb, plist, icns.')
cmd.set_defaults(func=cli_compose)
cmd.epilog = '''
@@ -144,7 +155,7 @@ Notes:
'-v', '--verbose', action='store_true',
help='print all keys with offsets and sizes')
cmd.add_argument(
'file', nargs='+', type=PathExist('f'), metavar='FILE',
'file', nargs='+', type=PathExist('f', stdin=True), metavar='FILE',
help='One or more .icns files.')
cmd.set_defaults(func=cli_print)
@@ -156,7 +167,7 @@ Notes:
'-q', '--quiet', action='store_true',
help='do not print OK results')
cmd.add_argument(
'file', nargs='+', type=PathExist('f'), metavar='FILE',
'file', nargs='+', type=PathExist('f', stdin=True), metavar='FILE',
help='One or more .icns files.')
cmd.set_defaults(func=cli_verify)

57
setup.py Normal file
View File

@@ -0,0 +1,57 @@
#!/usr/bin/env python3
from setuptools import setup
from icnsutil import __doc__, __version__
with open('README.md') as fp:
longdesc = fp.read()
setup(
name='icnsutil',
description=__doc__.strip(),
version=__version__,
author='relikd',
url='https://github.com/relikd/icnsutil',
license='MIT',
packages=['icnsutil'],
entry_points={
'console_scripts': [
'icnsutil=icnsutil.cli:main'
]
},
extras_require={
'convert': ['Pillow'],
},
long_description_content_type="text/markdown",
long_description=longdesc,
python_requires='>=3.2',
keywords=[
'icns',
'icon',
'extract',
'compose',
'create',
],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Environment :: MacOS X',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Topic :: Desktop Environment',
'Topic :: Multimedia :: Graphics :: Graphics Conversion',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Utilities',
],
)

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env python3
import os
import sys
import zipfile
import os # makedirs
from zipfile import ZipFile
from random import randint
if __name__ == '__main__':
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
import sys
sys.path[0] = os.path.dirname(sys.path[0])
from icnsutil import IcnsFile, PackBytes
@@ -62,7 +62,7 @@ def generate_raw_rgb():
def generate_icns():
os.makedirs('format-support-icns', exist_ok=True)
with zipfile.ZipFile('format-support-raw.zip') as Zip:
with ZipFile('format-support-raw.zip') as Zip:
for s, keys in INFO.items():
print('generate icns for {}x{}'.format(s, s))
for key in keys:
@@ -91,7 +91,7 @@ def generate_icns():
def generate_random_it32_header():
print('testing random it32 header')
os.makedirs('format-support-it32', exist_ok=True)
with zipfile.ZipFile('format-support-raw.zip') as Zip:
with ZipFile('format-support-raw.zip') as Zip:
with Zip.open('128x128.rgb') as f:
data = f.read()

View File

@@ -2,9 +2,9 @@
import unittest
import shutil # rmtree
import os # chdir, listdir, makedirs, path, remove
import sys
if __name__ == '__main__':
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
import sys
sys.path[0] = os.path.dirname(sys.path[0])
from icnsutil import *
@@ -68,6 +68,11 @@ class TestArgbImage(unittest.TestCase):
self.assertEqual(img.size, (16, 16))
self.assertEqual(img.a, [255] * 16 * 16)
@unittest.skipUnless(PIL_ENABLED, 'PIL_ENABLED == False')
def test_attributes(self):
# will raise AttributeError if _load_png didnt init all attrributes
str(ArgbImage(file='rgb.icns.png'))
def test_data_getter(self):
img = ArgbImage(file='rgb.icns.argb')
argb = img.argb_data(compress=True)
@@ -115,9 +120,9 @@ class TestIcnsFile(unittest.TestCase):
['info', 'ic12', 'icsb', 'sb24', 'ic04',
'SB24', 'ic05', 'icsB', 'ic11', 'slct'])
# Not an ICNS file
with self.assertRaises(TypeError):
with self.assertRaises(RawData.ParserError):
IcnsFile(file='rgb.icns.argb')
with self.assertRaises(TypeError):
with self.assertRaises(RawData.ParserError):
IcnsFile(file='rgb.icns.png')
def test_load_file(self):
@@ -195,6 +200,32 @@ class TestIcnsFile(unittest.TestCase):
is_invalid = any(IcnsFile.verify('selected.icns'))
self.assertEqual(is_invalid, False)
def test_description(self):
str = IcnsFile.description('rgb.icns', indent=0)
self.assertEqual(str, '''
ICN#: 256 bytes, iconmask: 32x32-mono
il32: 2224 bytes, rgb: 32x32
l8mk: 1024 bytes, mask: 32x32
ics#: 64 bytes, iconmask: 16x16-mono
is32: 705 bytes, rgb: 16x16
s8mk: 256 bytes, mask: 16x16
it32: 14005 bytes, rgb: 128x128
t8mk: 16384 bytes, mask: 128x128
'''.lstrip().replace('\n', os.linesep))
str = IcnsFile.description('selected.icns', verbose=True, indent=0)
self.assertEqual(str, '''
info: 314 bytes, offset: 8, plist: info
ic12: 1863 bytes, offset: 330, png: 32x32@2x
icsb: 271 bytes, offset: 2201, argb: 18x18
sb24: 748 bytes, offset: 2480, png: 24x24
ic04: 215 bytes, offset: 3236, argb: 16x16
SB24: 1681 bytes, offset: 3459, png: 24x24@2x
ic05: 690 bytes, offset: 5148, argb: 32x32
icsB: 1001 bytes, offset: 5846, png: 18x18@2x
ic11: 1056 bytes, offset: 6855, png: 16x16@2x
slct: 7660 bytes, offset: 7919, icns: selected
'''.lstrip().replace('\n', os.linesep))
class TestIcnsType(unittest.TestCase):
def test_sizes(self):
@@ -238,6 +269,17 @@ class TestIcnsType(unittest.TestCase):
self.assertEqual(x.size, (256, 256))
self.assertEqual(x.compressable, False)
self.assertEqual(x.availability, 10.5)
# Test rgb is detected by filename extension
with open('rgb.icns.rgb', 'rb') as fp:
x = IcnsType.guess(fp.read(), 'rgb.icns.rgb')
self.assertTrue(x.is_type('rgb'))
self.assertEqual(x.size, (16, 16))
self.assertEqual(x.retina, False)
self.assertEqual(x.channels, 3)
self.assertEqual(x.compressable, True)
fp.seek(0)
with self.assertRaises(IcnsType.CanNotDetermine):
x = IcnsType.guess(fp.read(), 'rgb.icns.bin')
def test_img_mask_pairs(self):
for x, y in IcnsType.enum_img_mask_pairs(['t8mk']):
@@ -310,9 +352,9 @@ class TestIcnsType(unittest.TestCase):
def test_exceptions(self):
with self.assertRaises(NotImplementedError):
IcnsType.get('wrong key')
with self.assertRaises(ValueError):
with self.assertRaises(IcnsType.CanNotDetermine):
IcnsType.guess(b'\x00')
with self.assertRaises(ValueError): # could be any icns
with self.assertRaises(IcnsType.CanNotDetermine): # could be any icns
with open('rgb.icns', 'rb') as fp:
IcnsType.guess(fp.read(6))
@@ -553,8 +595,8 @@ class TestIcp4RGB(TestExport):
self.OUTDIR, fname)), msg='File does not exist: ' + fname)
if PIL_ENABLED:
class TestRGB_toPNG(TestExport):
@unittest.skipUnless(PIL_ENABLED, 'PIL_ENABLED == False')
class TestRGB_toPNG(TestExport):
INFILE = 'rgb.icns'
ARGS = {'convert_png': True}
@@ -567,7 +609,9 @@ if PIL_ENABLED:
self.assertEqual(self.img.media['l8mk'], img.mask_data())
self.assertTrue(self.outfiles['il32'].endswith('.png'))
class TestARGB_toPNG(TestExport):
@unittest.skipUnless(PIL_ENABLED, 'PIL_ENABLED == False')
class TestARGB_toPNG(TestExport):
INFILE = 'selected.icns'
ARGS = {'convert_png': True}
@@ -582,7 +626,9 @@ if PIL_ENABLED:
self.assertEqual(self.img.media['ic04'], img.argb_data())
self.assertTrue(self.outfiles['ic04'].endswith('.png'))
class TestNested_toPNG(TestExport):
@unittest.skipUnless(PIL_ENABLED, 'PIL_ENABLED == False')
class TestNested_toPNG(TestExport):
INFILE = 'selected.icns'
ARGS = {'convert_png': True, 'recursive': True}
@@ -593,7 +639,9 @@ if PIL_ENABLED:
fname = self.outfiles['slct']['ic05']
self.assertTrue(fname.endswith('.png'))
class TestPngOnlyNested_toPNG(TestExport):
@unittest.skipUnless(PIL_ENABLED, 'PIL_ENABLED == False')
class TestPngOnlyNested_toPNG(TestExport):
INFILE = 'selected.icns'
ARGS = {'allowed_ext': 'png', 'convert_png': True, 'recursive': True}
@@ -601,7 +649,9 @@ if PIL_ENABLED:
self.assertExportCount(8 + 1)
self.assertExportCount(8, self.outfiles['slct']['_'] + '.export')
class TestIcp4RGB_toPNG(TestExport):
@unittest.skipUnless(PIL_ENABLED, 'PIL_ENABLED == False')
class TestIcp4RGB_toPNG(TestExport):
INFILE = 'icp4rgb.icns'
ARGS = {'convert_png': True}