Merge branch 'master' into devel
This commit is contained in:
commit
03bdd3bf9b
23 changed files with 313 additions and 194 deletions
|
|
@ -1,3 +1,7 @@
|
|||
Jul 11, 2013 - v0.2.2 Fixed mistakes with trove classifier, pypi releases.
|
||||
|
||||
Jul 11, 2013 - v0.2.0 Support for Python 2.7 on windows, OpenJPEG 1.5.1.
|
||||
|
||||
Jun 27, 2013 - v0.1.10 Can wrap codestreams in custom JP2 jackets. Exposing
|
||||
parameter to specify multi component transform. Added a raw codestream
|
||||
file.
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ copyright = u'2013, John Evans'
|
|||
# The short X.Y version.
|
||||
version = '0.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.1.10'
|
||||
release = '0.2.2'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
|
|
|||
|
|
@ -7,15 +7,15 @@ Glymur Configuration
|
|||
''''''''''''''''''''''
|
||||
|
||||
The default glymur installation process relies upon OpenJPEG version
|
||||
1.5.1 being properly installed on your system. This will, however,
|
||||
only give you you basic read capabilities, so if you wish to take
|
||||
advantage of more of glymur's features, you should compile OpenJPEG as
|
||||
a shared library from the developmental source that you can retrieve
|
||||
via subversion. As of this time of writing, svn revision 2345 works.
|
||||
You should also download the test data for the purpose of configuring
|
||||
and running OpenJPEG's test suite, check their instructions for all this.
|
||||
You should set the **OPJ_DATA_ROOT** environment variable for the purpose
|
||||
of running Glymur's test suite. ::
|
||||
1.5.1 being properly installed on your system. This will, however, only
|
||||
give you you basic read capabilities, so if you wish to take advantage
|
||||
of more of glymur's features, you should compile OpenJPEG as a shared
|
||||
library (named *openjp2* instead of *openjpeg*) from the developmental
|
||||
source that you can retrieve via subversion. As of this time of writing,
|
||||
svn revision 2345 works. You should also download the test data for
|
||||
the purpose of configuring and running OpenJPEG's test suite, check
|
||||
their instructions for all this. You should set the **OPJ_DATA_ROOT**
|
||||
environment variable for the purpose of running Glymur's test suite. ::
|
||||
|
||||
$ svn co http://openjpeg.googlecode.com/svn/data
|
||||
$ export OPJ_DATA_ROOT=`pwd`/data
|
||||
|
|
@ -32,13 +32,16 @@ the openjp2 library. You may create the configuration file as follows::
|
|||
> openjp2: /opt/openjp2-svn/lib/libopenjp2.so
|
||||
> EOF
|
||||
|
||||
That assumes, of course, that you've installed OpenJPEG into
|
||||
This assumes, of course, that you've installed OpenJPEG into
|
||||
/opt/openjp2-svn on a linux system. You may also substitute
|
||||
**$XDG_CONFIG_HOME** for **$HOME/.config**.
|
||||
|
||||
Again, though, the configuration file is not required if you only wish to
|
||||
read JPEG 2000 files using OpenJPEG version 1.5.1.
|
||||
You may also include a line for the version 1.5.1 library if you have it installed
|
||||
in a non-standard place, i.e. ::
|
||||
|
||||
[library]
|
||||
openjp2: /opt/openjp2-svn/lib/libopenjp2.so
|
||||
openjpeg: /not/the/usual/location/lib/libopenjpeg.so
|
||||
|
||||
'''''''''''''''''''''''''''''''''''''''''''
|
||||
Package Management Suggestions for Testing
|
||||
|
|
@ -65,13 +68,29 @@ additionally be installed:
|
|||
* py33-scikit-image and either py33-Pillow or freeimage
|
||||
* py33-matplotlib and py33-Pillow
|
||||
|
||||
MacPorts supplies both OpenJPEG 1.5.0 and OpenJPEG 2.0.0. As previously
|
||||
mentioned, the 2.0.0 official release is not supported (although the 2.0+
|
||||
development version via SVN *is* supported).
|
||||
|
||||
Linux
|
||||
-----
|
||||
|
||||
Fedora 19
|
||||
'''''''''
|
||||
Fedora 18 ships with Python 3.3 and all the necessary RPMs are available to
|
||||
run the maximum number of tests.
|
||||
|
||||
* python3
|
||||
* python3-numpy
|
||||
* python3-setuptools
|
||||
* python3-matplotlib (for running tests)
|
||||
* python3-matplotlib-tk (or whichever matplotlib backend you prefer)
|
||||
* python3-pillow (for running tests)
|
||||
|
||||
Fedora 18
|
||||
'''''''''
|
||||
Fedora 18 ships with Python 3.3, so all the necessary RPMs are available to
|
||||
meet the minimal set of requirements.
|
||||
Fedora 18 ships with Python 3.3 and the following RPMs are available to
|
||||
meet the minimal set of requirements for running glymur.
|
||||
|
||||
* python3
|
||||
* python3-numpy
|
||||
|
|
@ -94,28 +113,6 @@ repositories::
|
|||
$ pip-python3 install Pillow --user
|
||||
$ export PYTHONPATH=$HOME/.local/lib/python3.3/site-packages:$PYTHONPATH
|
||||
|
||||
Raspbian
|
||||
''''''''
|
||||
Yeah, this was the first thing I tried after getting my new Raspberry
|
||||
Pi hooked up (couldn't help myself :-) Raspbian ships with Python
|
||||
3.2 and 2.7, so these steps detail working with 2.7.
|
||||
|
||||
Additional required OS packages include::
|
||||
|
||||
* python-pip
|
||||
* python-pkg-resources
|
||||
* python-mock
|
||||
|
||||
You must install contextlib2 via pip, and then you can run at least
|
||||
a minimal number of tests. To attempt to run more of the tests,
|
||||
install the following debs::
|
||||
|
||||
* python-dev
|
||||
* python-matplotlib
|
||||
|
||||
and then install Pillow via pip. The tests take about 30 minutes to run, with
|
||||
one unexpected failure as of the time of writing.
|
||||
|
||||
Fedora 17
|
||||
'''''''''
|
||||
Fedora 17 ships with Python 3.2 and 2.7, but OpenJPEG is only at version 1.4,
|
||||
|
|
@ -152,20 +149,21 @@ Windows
|
|||
-------
|
||||
The only configuration I've tested is Python(xy), which uses Python 2.7.
|
||||
Python(xy) already comes with numpy, but you will have to install pip and then
|
||||
contextlib2 as well. This configuration assumes you've installed OpenJPEG
|
||||
1.5.1.
|
||||
contextlib2 and mock as well. Both 1.5.1 and the svn development versions of
|
||||
openjpeg work.
|
||||
|
||||
|
||||
'''''''
|
||||
Testing
|
||||
'''''''
|
||||
|
||||
If you wish to run the tests (strongly suggested :-), you can either run them
|
||||
If you wish to run the tests (strongly recommended :-), you can either run them
|
||||
from within python as follows ... ::
|
||||
|
||||
>>> import glymur
|
||||
>>> glymur.runtests()
|
||||
|
||||
or from the unix command line. ::
|
||||
or from the command line. ::
|
||||
|
||||
$ cd /to/where/you/unpacked/glymur
|
||||
$ python -m unittest discover
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ about OpenJPEG, please consult http://www.openjpeg.org.
|
|||
If you use MacPorts on the mac or if you have a sufficiently recent version of
|
||||
Linux, your package manager should already provide you with at least version
|
||||
1.5.1 of OpenJPEG, which means that glymur can be installed ready to read JPEG
|
||||
2000 images. If you use windows, I suggest using the 1.5.1 windows installer provided
|
||||
to you by the OpenJPEG folks at
|
||||
2000 images. If you use windows, I suggest using the 1.5.1 windows installer
|
||||
provided to you by the OpenJPEG folks at
|
||||
https://code.google.com/p/openjpeg/downloads/list .
|
||||
|
||||
Glymur Installation
|
||||
|
|
@ -56,5 +56,5 @@ You can run the tests from within python as follows::
|
|||
>>> glymur.runtests()
|
||||
|
||||
Many tests are currently skipped; in fact most of them are skipped if you
|
||||
are relying on OpenJPEG 1.5.1. But the important thing is whether or not any
|
||||
tests fail.
|
||||
are relying on OpenJPEG 1.5.1. But the important thing, though, is whether or
|
||||
not any tests fail.
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ def nemo():
|
|||
file : str
|
||||
Platform-independent path to nemo.jp2.
|
||||
"""
|
||||
file = pkg_resources.resource_filename(__name__, "nemo.jp2")
|
||||
return file
|
||||
filename = pkg_resources.resource_filename(__name__, "nemo.jp2")
|
||||
return filename
|
||||
|
||||
|
||||
def goodstuff():
|
||||
|
|
@ -29,5 +29,5 @@ def goodstuff():
|
|||
file : str
|
||||
Platform-independent path to goodstuff.j2k.
|
||||
"""
|
||||
file = pkg_resources.resource_filename(__name__, "goodstuff.j2k")
|
||||
return file
|
||||
filename = pkg_resources.resource_filename(__name__, "goodstuff.j2k")
|
||||
return filename
|
||||
|
|
|
|||
|
|
@ -38,11 +38,13 @@ _METHOD_DISPLAY = {
|
|||
ANY_ICC_PROFILE: 'any ICC profile',
|
||||
VENDOR_COLOR_METHOD: 'vendor color method'}
|
||||
|
||||
_ = {1: 'accurately represents correct colorspace definition',
|
||||
2: 'approximates correct colorspace definition, exceptional quality',
|
||||
3: 'approximates correct colorspace definition, reasonable quality',
|
||||
4: 'approximates correct colorspace definition, poor quality'}
|
||||
_approximation_display = _
|
||||
_APPROX_DISPLAY = {1: 'accurately represents correct colorspace definition',
|
||||
2: 'approximates correct colorspace definition, '
|
||||
+ 'exceptional quality',
|
||||
3: 'approximates correct colorspace definition, '
|
||||
+ 'reasonable quality',
|
||||
4: 'approximates correct colorspace definition, '
|
||||
+ 'poor quality'}
|
||||
|
||||
|
||||
class Jp2kBox(object):
|
||||
|
|
@ -66,12 +68,15 @@ class Jp2kBox(object):
|
|||
self.offset = offset
|
||||
self.longname = longname
|
||||
|
||||
# should never be used except for last box in file.
|
||||
self._file_size = -1
|
||||
|
||||
def __str__(self):
|
||||
msg = "{0} Box ({1})".format(self.longname, self.box_id)
|
||||
msg += " @ ({0}, {1})".format(self.offset, self.length)
|
||||
return msg
|
||||
|
||||
def write(self, fptr):
|
||||
def write(self, _):
|
||||
"""Must be implemented in a subclass.
|
||||
"""
|
||||
msg = "Not supported for {0} box.".format(self.longname)
|
||||
|
|
@ -120,7 +125,7 @@ class Jp2kBox(object):
|
|||
|
||||
# Call the proper parser for the given box with ID "T".
|
||||
try:
|
||||
box = _BOX_WITH_ID[box_id]._parse(fptr, start, num_bytes)
|
||||
box = _BOX_WITH_ID[box_id].parse(fptr, start, num_bytes)
|
||||
except KeyError:
|
||||
msg = 'Unrecognized box ({0}) encountered.'.format(box_id)
|
||||
warnings.warn(msg)
|
||||
|
|
@ -177,6 +182,7 @@ class ColourSpecificationBox(Jp2kBox):
|
|||
ICC profile header according to ICC profile specification. If
|
||||
colorspace is not None, then icc_profile must be empty.
|
||||
"""
|
||||
|
||||
def __init__(self, method=ENUMERATED_COLORSPACE, precedence=0,
|
||||
approximation=0, colorspace=None, icc_profile=None,
|
||||
length=0, offset=-1):
|
||||
|
|
@ -203,8 +209,9 @@ class ColourSpecificationBox(Jp2kBox):
|
|||
msg += '\n Precedence: {0}'.format(self.precedence)
|
||||
|
||||
if self.approximation is not 0:
|
||||
dispvalue = _approximation_display[self.approximation]
|
||||
dispvalue = _APPROX_DISPLAY[self.approximation]
|
||||
msg += '\n Approximation: {0}'.format(dispvalue)
|
||||
|
||||
if self.colorspace is not None:
|
||||
dispvalue = _COLORSPACE_MAP_DISPLAY[self.colorspace]
|
||||
msg += '\n Colorspace: {0}'.format(dispvalue)
|
||||
|
|
@ -240,7 +247,7 @@ class ColourSpecificationBox(Jp2kBox):
|
|||
fptr.write(read_buffer)
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse JPEG 2000 color specification box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -468,7 +475,7 @@ class ChannelDefinitionBox(Jp2kBox):
|
|||
self.association[j]))
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse component definition box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -542,7 +549,7 @@ class ComponentMappingBox(Jp2kBox):
|
|||
return msg
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse component mapping box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -607,7 +614,7 @@ class ContiguousCodestreamBox(Jp2kBox):
|
|||
return msg
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset=0, length=0):
|
||||
def parse(fptr, offset=0, length=0):
|
||||
"""Parse a codestream box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -685,7 +692,7 @@ class FileTypeBox(Jp2kBox):
|
|||
fptr.write(item.encode())
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse JPEG 2000 file type box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -812,7 +819,7 @@ class ImageHeaderBox(Jp2kBox):
|
|||
fptr.write(read_buffer)
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse JPEG 2000 image header box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -883,7 +890,7 @@ class AssociationBox(Jp2kBox):
|
|||
return msg
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse association box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -956,7 +963,7 @@ class JP2HeaderBox(Jp2kBox):
|
|||
fptr.seek(end_pos)
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse JPEG 2000 header box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1017,7 +1024,7 @@ class JPEG2000SignatureBox(Jp2kBox):
|
|||
fptr.write(struct.pack('>BBBB', *self.signature))
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse JPEG 2000 signature box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1073,7 +1080,7 @@ class PaletteBox(Jp2kBox):
|
|||
return msg
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse palette box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1220,6 +1227,8 @@ _READER_REQUIREMENTS_DISPLAY = {
|
|||
+ 'requirements in M.9.2.3',
|
||||
73: 'YPbPr(1125/60) enumerated colourspace',
|
||||
74: 'YPbPr(1250/50) enumerated colourspace'}
|
||||
|
||||
|
||||
class ReaderRequirementsBox(Jp2kBox):
|
||||
"""Container for reader requirements box information.
|
||||
|
||||
|
|
@ -1276,7 +1285,7 @@ class ReaderRequirementsBox(Jp2kBox):
|
|||
return msg
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse reader requirements box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1380,7 +1389,7 @@ class ResolutionBox(Jp2kBox):
|
|||
return msg
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse Resolution box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1436,7 +1445,7 @@ class CaptureResolutionBox(Jp2kBox):
|
|||
return msg
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse Resolution box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1493,7 +1502,7 @@ class DisplayResolutionBox(Jp2kBox):
|
|||
return msg
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse Resolution box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1548,7 +1557,7 @@ class LabelBox(Jp2kBox):
|
|||
return msg
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse Label box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1633,7 +1642,7 @@ class XMLBox(Jp2kBox):
|
|||
fptr.write(read_buffer)
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse XML box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1697,7 +1706,7 @@ class UUIDListBox(Jp2kBox):
|
|||
return(msg)
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse UUIDList box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1760,7 +1769,7 @@ class UUIDInfoBox(Jp2kBox):
|
|||
return(msg)
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse UUIDInfo super box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1828,7 +1837,7 @@ class DataEntryURLBox(Jp2kBox):
|
|||
return msg
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse Data Entry URL box.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1949,7 +1958,7 @@ class UUIDBox(Jp2kBox):
|
|||
return msg
|
||||
|
||||
@staticmethod
|
||||
def _parse(fptr, offset, length):
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse UUID box.
|
||||
|
||||
Parameters
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
# Parse the file for JP2/JPX contents only if we are reading it.
|
||||
if mode == 'rb':
|
||||
self._parse()
|
||||
self.parse()
|
||||
|
||||
def __str__(self):
|
||||
metadata = ['File: ' + os.path.basename(self.filename)]
|
||||
|
|
@ -110,7 +110,7 @@ class Jp2k(Jp2kBox):
|
|||
metadata.append(str(codestream))
|
||||
return '\n'.join(metadata)
|
||||
|
||||
def _parse(self):
|
||||
def parse(self):
|
||||
"""Parses the JPEG 2000 file.
|
||||
|
||||
Raises
|
||||
|
|
@ -425,7 +425,7 @@ class Jp2k(Jp2kBox):
|
|||
_opj2.destroy_codec(codec)
|
||||
_opj2.image_destroy(image)
|
||||
|
||||
self._parse()
|
||||
self.parse()
|
||||
|
||||
def wrap(self, filename, boxes=None):
|
||||
"""Write the codestream back out to file, wrapped in new JP2 jacket.
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ import warnings
|
|||
import sys
|
||||
if sys.hexversion <= 0x03000000:
|
||||
from ConfigParser import SafeConfigParser as ConfigParser
|
||||
from ConfigParser import NoOptionError
|
||||
else:
|
||||
from configparser import ConfigParser
|
||||
from configparser import NoOptionError
|
||||
|
||||
|
||||
def glymurrc_fname():
|
||||
|
|
@ -28,7 +30,6 @@ def glymurrc_fname():
|
|||
if os.path.exists(fname):
|
||||
return fname
|
||||
|
||||
# Either GLYMURCONFIGDIR/glymurrc or $HOME/.glymur/glymurrc
|
||||
confdir = get_configdir()
|
||||
if confdir is not None:
|
||||
fname = os.path.join(confdir, 'glymurrc')
|
||||
|
|
@ -39,10 +40,12 @@ def glymurrc_fname():
|
|||
return None
|
||||
|
||||
|
||||
def get_openjpeg_config():
|
||||
""" Try to find openjpeg library on the system path first.
|
||||
def load_openjpeg(libopenjpeg_path):
|
||||
"""Load the openjpeg library, falling back on defaults if necessary.
|
||||
"""
|
||||
libopenjpeg_path = find_library('openjpeg')
|
||||
if libopenjpeg_path is None:
|
||||
# Let ctypes try to find it.
|
||||
libopenjpeg_path = find_library('openjpeg')
|
||||
|
||||
# If we could not find it, then look in some likely locations.
|
||||
if libopenjpeg_path is None:
|
||||
|
|
@ -74,19 +77,34 @@ def get_openjpeg_config():
|
|||
return openjpeg_lib
|
||||
|
||||
|
||||
def get_openjp2_config():
|
||||
def read_config_file():
|
||||
"""
|
||||
We expect to not find openjp2 on the system path since the only version
|
||||
that we currently care about is still in the svn trunk at openjpeg.org.
|
||||
We must use a configuration file that the user must write.
|
||||
"""
|
||||
lib = {'openjp2': None, 'openjpeg': None}
|
||||
filename = glymurrc_fname()
|
||||
if filename is not None:
|
||||
# Read the configuration file for the library location.
|
||||
parser = ConfigParser()
|
||||
parser.read(filename)
|
||||
libopenjp2_path = parser.get('library', 'openjp2')
|
||||
else:
|
||||
try:
|
||||
lib['openjp2'] = parser.get('library', 'openjp2')
|
||||
except NoOptionError:
|
||||
pass
|
||||
try:
|
||||
lib['openjpeg'] = parser.get('library', 'openjpeg')
|
||||
except NoOptionError:
|
||||
pass
|
||||
|
||||
return lib
|
||||
|
||||
|
||||
def load_openjp2(libopenjp2_path):
|
||||
"""Load the openjp2 library, falling back on defaults if necessary.
|
||||
"""
|
||||
if libopenjp2_path is None:
|
||||
# No help from the config file, try to find it ourselves.
|
||||
libopenjp2_path = find_library('openjp2')
|
||||
|
||||
|
|
@ -98,20 +116,22 @@ def get_openjp2_config():
|
|||
openjp2_lib = ctypes.windll.LoadLibrary(libopenjp2_path)
|
||||
else:
|
||||
openjp2_lib = ctypes.CDLL(libopenjp2_path)
|
||||
except OSError:
|
||||
except (TypeError, OSError):
|
||||
msg = '"Library {0}" could not be loaded. Operating in degraded mode.'
|
||||
msg = msg.format(libopenjp2_path)
|
||||
warnings.warn(msg, UserWarning)
|
||||
openjp2_lib = None
|
||||
|
||||
return openjp2_lib
|
||||
|
||||
|
||||
def glymur_config():
|
||||
"""Try to ascertain locations of openjp2, openjpeg libraries.
|
||||
"""
|
||||
openjp2_lib = get_openjp2_config()
|
||||
openjpeg_lib = get_openjpeg_config()
|
||||
return openjp2_lib, openjpeg_lib
|
||||
libs = read_config_file()
|
||||
libopenjp2_handle = load_openjp2(libs['openjp2'])
|
||||
libopenjpeg_handle = load_openjpeg(libs['openjpeg'])
|
||||
return libopenjp2_handle, libopenjpeg_handle
|
||||
|
||||
|
||||
def get_configdir():
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pylint: disable-all
|
||||
import doctest
|
||||
import os
|
||||
import pkg_resources
|
||||
|
|
@ -12,6 +13,7 @@ import numpy as np
|
|||
import glymur
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
@unittest.skipIf(glymur.lib._openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestOpenJP2(unittest.TestCase):
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#pylint: disable-all
|
||||
import ctypes
|
||||
import unittest
|
||||
|
||||
import glymur
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib._openjpeg.OPENJPEG is None,
|
||||
"Missing openjpeg library.")
|
||||
class TestOpenJPEG(unittest.TestCase):
|
||||
|
|
@ -35,4 +37,3 @@ class TestOpenJPEG(unittest.TestCase):
|
|||
self.assertEqual(dp.jpwl_max_tiles, 0)
|
||||
self.assertEqual(dp.cp_limit_decoding, 0)
|
||||
self.assertEqual(dp.flags, 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,19 +3,19 @@ import sys
|
|||
|
||||
import numpy as np
|
||||
|
||||
def mse(A, B):
|
||||
|
||||
def mse(amat, bmat):
|
||||
"""Mean Square Error"""
|
||||
diff = A.astype(np.double) - B.astype(np.double)
|
||||
#e = np.sqrt(np.mean(diff**2))
|
||||
e = np.mean(diff**2)
|
||||
return e
|
||||
diff = amat.astype(np.double) - bmat.astype(np.double)
|
||||
err = np.mean(diff**2)
|
||||
return err
|
||||
|
||||
|
||||
def peak_tolerance(A, B):
|
||||
def peak_tolerance(amat, bmat):
|
||||
"""Peak Tolerance"""
|
||||
diff = np.abs(A.astype(np.double) - B.astype(np.double))
|
||||
p = diff.max()
|
||||
return p
|
||||
diff = np.abs(amat.astype(np.double) - bmat.astype(np.double))
|
||||
ptol = diff.max()
|
||||
return ptol
|
||||
|
||||
|
||||
def read_pgx(pgx_file):
|
||||
|
|
@ -28,42 +28,42 @@ def read_pgx(pgx_file):
|
|||
PG%[ \t]%c%c%[ \t+-]%d%[ \t]%d%[ \t]%d"
|
||||
"""
|
||||
header = ''
|
||||
with open(pgx_file, 'rb') as fp:
|
||||
with open(pgx_file, 'rb') as fptr:
|
||||
while True:
|
||||
x = fp.read(1)
|
||||
if x[0] == 10 or x == '\n':
|
||||
pos = fp.tell()
|
||||
char = fptr.read(1)
|
||||
if char[0] == 10 or char == '\n':
|
||||
pos = fptr.tell()
|
||||
break
|
||||
else:
|
||||
if sys.hexversion < 0x03000000:
|
||||
header += x
|
||||
header += char
|
||||
else:
|
||||
header += chr(x[0])
|
||||
header += chr(char[0])
|
||||
|
||||
header = header.rstrip()
|
||||
n = re.split('\s', header)
|
||||
tokens = re.split('\s', header)
|
||||
|
||||
if (n[1][0] == 'M') and (sys.byteorder == 'little'):
|
||||
if (tokens[1][0] == 'M') and (sys.byteorder == 'little'):
|
||||
swapbytes = True
|
||||
elif (n[1][0] == 'L') and (sys.byteorder == 'big'):
|
||||
elif (tokens[1][0] == 'L') and (sys.byteorder == 'big'):
|
||||
swapbytes = True
|
||||
else:
|
||||
swapbytes = False
|
||||
|
||||
if (len(n) == 6):
|
||||
bitdepth = int(n[3])
|
||||
if (len(tokens) == 6):
|
||||
bitdepth = int(tokens[3])
|
||||
signed = bitdepth < 0
|
||||
if signed:
|
||||
bitdepth = -1 * bitdepth
|
||||
nrows = int(n[5])
|
||||
ncols = int(n[4])
|
||||
nrows = int(tokens[5])
|
||||
ncols = int(tokens[4])
|
||||
else:
|
||||
bitdepth = int(n[2])
|
||||
bitdepth = int(tokens[2])
|
||||
signed = bitdepth < 0
|
||||
if signed:
|
||||
bitdepth = -1 * bitdepth
|
||||
nrows = int(n[4])
|
||||
ncols = int(n[3])
|
||||
nrows = int(tokens[4])
|
||||
ncols = int(tokens[3])
|
||||
|
||||
if signed:
|
||||
if bitdepth <= 8:
|
||||
|
|
@ -84,10 +84,8 @@ def read_pgx(pgx_file):
|
|||
|
||||
# Reopen the file in binary mode and seek to the start of the binary
|
||||
# data
|
||||
with open(pgx_file, 'rb') as fp:
|
||||
fp.seek(pos)
|
||||
data = np.fromfile(file=fp, dtype=dtype).reshape(shape)
|
||||
with open(pgx_file, 'rb') as fptr:
|
||||
fptr.seek(pos)
|
||||
data = np.fromfile(file=fptr, dtype=dtype).reshape(shape)
|
||||
|
||||
return(data.byteswap(swapbytes))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pylint: disable-all
|
||||
import os
|
||||
import pkg_resources
|
||||
import re
|
||||
|
|
@ -29,6 +30,7 @@ class TestCallbacks(unittest.TestCase):
|
|||
# Restore stdout.
|
||||
sys.stdout = self.stdout
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_info_callback_on_write(self):
|
||||
# Verify the messages printed when writing an image in verbose mode.
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
|
|
@ -96,9 +98,12 @@ class TestCallbacks15(unittest.TestCase):
|
|||
actual = sys.stdout.getvalue().strip()
|
||||
|
||||
regex = re.compile(r"""\[INFO\]\stile\s1\sof\s1\s+
|
||||
\[INFO\]\s-\stiers-1\stook\s[0-9]+\.[0-9]+\ss\s+
|
||||
\[INFO\]\s-\sdwt\stook\s[0-9]+\.[0-9]+\ss\s+
|
||||
\[INFO\]\s-\stile\sdecoded\sin\s[0-9]+\.[0-9]+\ss""",
|
||||
\[INFO\]\s-\stiers-1\stook\s
|
||||
[0-9]+\.[0-9]+\ss\s+
|
||||
\[INFO\]\s-\sdwt\stook\s
|
||||
(-){0,1}[0-9]+\.[0-9]+\ss\s+
|
||||
\[INFO\]\s-\stile\sdecoded\sin\s
|
||||
[0-9]+\.[0-9]+\ss""",
|
||||
re.VERBOSE)
|
||||
if sys.hexversion <= 0x03020000:
|
||||
self.assertRegexpMatches(actual, regex)
|
||||
|
|
@ -106,6 +111,5 @@ class TestCallbacks15(unittest.TestCase):
|
|||
self.assertRegex(actual, regex)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pylint: disable-all
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
|
|
@ -29,6 +30,7 @@ class TestCodestream(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_reserved_marker_segment(self):
|
||||
# Some marker segments were reserved in FCD15444-1. Since that
|
||||
# standard is old, some of them may have come into use.
|
||||
|
|
@ -58,6 +60,7 @@ class TestCodestream(unittest.TestCase):
|
|||
self.assertEqual(c.segment[2].length, 3)
|
||||
self.assertEqual(c.segment[2]._data, b'\x00')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_unknown_marker_segment(self):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"""These tests are for edge cases where OPENJPEG does not exist, but
|
||||
"""These tests are for edge cases where OPENJPEG does not exist, but
|
||||
OPENJP2 may be present in some form or other.
|
||||
"""
|
||||
#pylint: disable-all
|
||||
|
||||
import imp
|
||||
import os
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pylint: disable-all
|
||||
import datetime
|
||||
import os
|
||||
import struct
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pylint: disable-all
|
||||
import doctest
|
||||
import os
|
||||
import tempfile
|
||||
|
|
@ -14,10 +15,14 @@ from glymur.jp2box import *
|
|||
|
||||
# Doc tests should be run as well.
|
||||
def load_tests(loader, tests, ignore):
|
||||
if os.name == "nt":
|
||||
# Can't do it on windows, temporary file issue.
|
||||
return tests
|
||||
tests.addTests(doctest.DocTestSuite('glymur.jp2box'))
|
||||
return tests
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestChannelDefinition(unittest.TestCase):
|
||||
|
|
@ -232,6 +237,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
association=[1, 2, 3])
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
class TestXML(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
@ -291,7 +297,7 @@ class TestXML(unittest.TestCase):
|
|||
with self.assertRaises((IOError, OSError)) as ce:
|
||||
xmlb = glymur.jp2box.XMLBox(filename=self.xmlfile, xml=xml_object)
|
||||
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
"Problems using NamedTemporaryFile on windows.")
|
||||
def test_basic_xml(self):
|
||||
# Should be able to write an XMLBox.
|
||||
|
|
@ -313,7 +319,7 @@ class TestXML(unittest.TestCase):
|
|||
self.assertEqual(ET.tostring(jp2.box[3].xml),
|
||||
b'<data>0</data>')
|
||||
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
"Problems using NamedTemporaryFile on windows.")
|
||||
def test_xml_from_file(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
|
@ -359,7 +365,7 @@ class TestColourSpecificationBox(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
"Problems using NamedTemporaryFile on windows.")
|
||||
def test_color_specification_box_with_out_enumerated_colorspace(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
|
@ -370,6 +376,7 @@ class TestColourSpecificationBox(unittest.TestCase):
|
|||
with self.assertRaises(NotImplementedError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_missing_colr_box(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
|
|
@ -501,12 +508,14 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
self.assertEqual(jp2.box[2].box[1].colorspace, glymur.core.SRGB)
|
||||
self.assertIsNone(jp2.box[2].box[1].icc_profile)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_wrap(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
j2k.wrap(tfile.name)
|
||||
self.verify_wrapped_raw(tfile.name)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_wrap_jp2(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
|
|
@ -514,6 +523,7 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
boxes = [box.box_id for box in jp2.box]
|
||||
self.assertEqual(boxes, ['jP ', 'ftyp', 'jp2h', 'jp2c'])
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_default_layout_but_with_specified_boxes(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
boxes = [JPEG2000SignatureBox(),
|
||||
|
|
@ -532,6 +542,7 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
self.verify_wrapped_raw(tfile.name)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_image_header_box_not_first_in_jp2_header(self):
|
||||
# The specification says that ihdr must be the first box in jp2h.
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
|
@ -551,6 +562,7 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_first_2_boxes_not_jP_and_ftyp(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
|
|
@ -571,6 +583,7 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_jp2h_not_preceeding_jp2c(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
|
|
@ -591,6 +604,7 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_missing_codestream(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import contextlib
|
||||
import ctypes
|
||||
# pylint: disable-all
|
||||
import doctest
|
||||
import imp
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
|
|
@ -33,14 +31,18 @@ except:
|
|||
|
||||
# Doc tests should be run as well.
|
||||
def load_tests(loader, tests, ignore):
|
||||
if os.name == "nt":
|
||||
# Can't do it on windows, temporary file issue.
|
||||
return tests
|
||||
if glymur.lib.openjp2.OPENJP2 is not None:
|
||||
tests.addTests(doctest.DocTestSuite('glymur.jp2k'))
|
||||
return tests
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestJp2k(unittest.TestCase):
|
||||
class TestJp2kBadXmlFile(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
|
@ -88,14 +90,6 @@ class TestJp2k(unittest.TestCase):
|
|||
with self.assertWarns(UserWarning) as cw:
|
||||
jp2k = Jp2k(self._bad_xml_file)
|
||||
|
||||
def test_rlevel_max(self):
|
||||
# Verify that rlevel=-1 gets us the lowest resolution image
|
||||
j = Jp2k(self.j2kfile)
|
||||
thumbnail1 = j.read(rlevel=-1)
|
||||
thumbnail2 = j.read(rlevel=5)
|
||||
np.testing.assert_array_equal(thumbnail1, thumbnail2)
|
||||
self.assertEqual(thumbnail1.shape, (25, 15, 3))
|
||||
|
||||
def test_invalid_xml_box(self):
|
||||
# Should be able to recover from xml box with bad xml.
|
||||
with warnings.catch_warnings():
|
||||
|
|
@ -107,6 +101,26 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(jp2k.box[3].length, 28)
|
||||
self.assertIsNone(jp2k.box[3].xml)
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestJp2k(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = glymur.data.nemo()
|
||||
self.j2kfile = glymur.data.goodstuff()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_rlevel_max(self):
|
||||
# Verify that rlevel=-1 gets us the lowest resolution image
|
||||
j = Jp2k(self.j2kfile)
|
||||
thumbnail1 = j.read(rlevel=-1)
|
||||
thumbnail2 = j.read(rlevel=5)
|
||||
np.testing.assert_array_equal(thumbnail1, thumbnail2)
|
||||
self.assertEqual(thumbnail1.shape, (25, 15, 3))
|
||||
|
||||
def test_bad_area_parameter(self):
|
||||
# Verify that we error out appropriately if given a bad area parameter.
|
||||
j = Jp2k(self.jp2file)
|
||||
|
|
@ -143,6 +157,7 @@ class TestJp2k(unittest.TestCase):
|
|||
filename = 'this file does not actually exist on the file system.'
|
||||
jp2k = Jp2k(filename)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_write_srgb_without_mct(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
expdata = j2k.read()
|
||||
|
|
@ -155,6 +170,7 @@ class TestJp2k(unittest.TestCase):
|
|||
c = ofile.get_codestream()
|
||||
self.assertEqual(c.segment[2].spcod[3], 0) # no mct
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_write_grayscale_with_mct(self):
|
||||
# MCT usage makes no sense for grayscale images.
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
|
@ -164,6 +180,7 @@ class TestJp2k(unittest.TestCase):
|
|||
with self.assertRaises(IOError):
|
||||
ofile.write(expdata[:, :, 0], mct=True)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_write_cprl(self):
|
||||
# Issue 17
|
||||
j = Jp2k(self.jp2file)
|
||||
|
|
@ -244,6 +261,7 @@ class TestJp2k(unittest.TestCase):
|
|||
jp2k = Jp2k(filename)
|
||||
self.assertEqual(len(jp2k.box), 0)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_64bit_XL_field(self):
|
||||
# Verify that boxes with the XL field are properly read.
|
||||
# Don't have such a file on hand, so we create one. Copy our example
|
||||
|
|
@ -276,6 +294,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(jp2k.box[5].offset, 3127)
|
||||
self.assertEqual(jp2k.box[5].length, 1133427 + 8)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_L_is_zero(self):
|
||||
# Verify that boxes with the L field as zero are correctly read.
|
||||
# This should only happen in the last box of a JPEG 2000 file.
|
||||
|
|
@ -331,6 +350,7 @@ class TestJp2k(unittest.TestCase):
|
|||
j = Jp2k(filename)
|
||||
self.assertEqual(j.box, [])
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_code_block_height_different_than_width(self):
|
||||
# Verify that we can set a code block size where height does not equal
|
||||
# width.
|
||||
|
|
@ -346,6 +366,7 @@ class TestJp2k(unittest.TestCase):
|
|||
# Code block size is reported as XY in the codestream.
|
||||
self.assertEqual(tuple(c.segment[2].spcod[5:7]), (3, 2))
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_negative_too_many_dimensions(self):
|
||||
# OpenJP2 only allows 2D or 3D images.
|
||||
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
|
||||
|
|
@ -354,6 +375,7 @@ class TestJp2k(unittest.TestCase):
|
|||
data = np.zeros((128, 128, 2, 2), dtype=np.uint8)
|
||||
j.write(data)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_unrecognized_jp2_colorspace(self):
|
||||
# We only allow RGB and GRAYSCALE.
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
|
|
@ -362,6 +384,7 @@ class TestJp2k(unittest.TestCase):
|
|||
data = np.zeros((128, 128, 3), dtype=np.uint8)
|
||||
j.write(data, colorspace='cmyk')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_2D_rgb(self):
|
||||
# RGB must have at least 3 components.
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
|
|
@ -370,6 +393,7 @@ class TestJp2k(unittest.TestCase):
|
|||
data = np.zeros((128, 128, 2), dtype=np.uint8)
|
||||
j.write(data, colorspace='rgb')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_colorspace_with_j2k(self):
|
||||
# Specifying a colorspace with J2K does not make sense.
|
||||
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
|
||||
|
|
@ -378,6 +402,7 @@ class TestJp2k(unittest.TestCase):
|
|||
data = np.zeros((128, 128, 3), dtype=np.uint8)
|
||||
j.write(data, colorspace='rgb')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_specify_rgb(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -385,6 +410,7 @@ class TestJp2k(unittest.TestCase):
|
|||
j.write(data, colorspace='rgb')
|
||||
self.assertEqual(j.box[2].box[1].colorspace, glymur.core.SRGB)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_specify_gray(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -393,6 +419,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(j.box[2].box[1].colorspace,
|
||||
glymur.core.GREYSCALE)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_specify_grey(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -401,6 +428,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(j.box[2].box[1].colorspace,
|
||||
glymur.core.GREYSCALE)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_grey_with_extra_component(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -412,6 +440,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(j.box[2].box[1].colorspace,
|
||||
glymur.core.GREYSCALE)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_grey_with_two_extra_components(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -423,6 +452,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(j.box[2].box[1].colorspace,
|
||||
glymur.core.GREYSCALE)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_rgb_with_extra_component(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -441,6 +471,7 @@ class TestJp2k(unittest.TestCase):
|
|||
data = np.zeros((128, 128, 3), dtype=np.uint8)
|
||||
j.write(data, colorspace='ycc')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_uinf_ulst_url_boxes(self):
|
||||
# Verify that we can read UINF, ULST, and URL boxes. I don't have
|
||||
# easy access to such a file, and there's no such file in the
|
||||
|
|
@ -497,6 +528,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(jp2k.box[3].box[1].flag, (0, 0, 0))
|
||||
self.assertEqual(jp2k.box[3].box[1].url, 'abcd')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_xml_box_with_trailing_nulls(self):
|
||||
# ElementTree does not like trailing null chars after valid XML
|
||||
# text.
|
||||
|
|
@ -526,6 +558,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(jp2k.box[3].offset, 77)
|
||||
self.assertEqual(jp2k.box[3].length, 36)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_asoc_label_box(self):
|
||||
# Construct a fake file with an asoc and a label box, as
|
||||
# OpenJPEG doesn't have such a file.
|
||||
|
|
@ -572,6 +605,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(jasoc.box[3].box[0].label, 'label')
|
||||
self.assertEqual(jasoc.box[3].box[1].box_id, 'xml ')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_openjpeg_library_message(self):
|
||||
# Verify the error message produced by the openjpeg library.
|
||||
# This will confirm that the error callback mechanism is working.
|
||||
|
|
@ -599,10 +633,10 @@ class TestJp2k(unittest.TestCase):
|
|||
Invalid\svalues\sfor\scomp\s=\s0\s+
|
||||
:\sdx=1\sdy=0''', re.VERBOSE)
|
||||
if sys.hexversion < 0x03020000:
|
||||
with self.assertRaisesRegexp((IOError, OSError), regexp) as ce:
|
||||
with self.assertRaisesRegexp((IOError, OSError), regexp):
|
||||
d = j.read(rlevel=1)
|
||||
else:
|
||||
with self.assertRaisesRegex((IOError, OSError), regexp) as ce:
|
||||
with self.assertRaisesRegex((IOError, OSError), regexp):
|
||||
d = j.read(rlevel=1)
|
||||
|
||||
def test_xmp_attribute(self):
|
||||
|
|
@ -616,6 +650,7 @@ class TestJp2k(unittest.TestCase):
|
|||
attr_value = elt.attrib['{0}CreatorTool'.format(ns1)]
|
||||
self.assertEqual(attr_value, 'glymur')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_unrecognized_exif_tag(self):
|
||||
# An unrecognized exif tag should be handled gracefully.
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
|
|
@ -671,42 +706,48 @@ class TestJp2k15(unittest.TestCase):
|
|||
pass
|
||||
|
||||
def test_bands(self):
|
||||
# Reading individual bands is an advanced maneuver.
|
||||
"""Reading individual bands is an advanced maneuver.
|
||||
"""
|
||||
jp2k = Jp2k(self.j2kfile)
|
||||
with self.assertRaises(NotImplementedError) as ce:
|
||||
jpdata = jp2k.read_bands()
|
||||
with self.assertRaises(NotImplementedError):
|
||||
jp2k.read_bands()
|
||||
|
||||
def test_area(self):
|
||||
# Area option not allowed for 1.5.1.
|
||||
"""Area option not allowed for 1.5.1.
|
||||
"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
with self.assertRaises(TypeError) as ce:
|
||||
d = j2k.read(area=(0, 0, 100, 100))
|
||||
with self.assertRaises(TypeError):
|
||||
j2k.read(area=(0, 0, 100, 100))
|
||||
|
||||
def test_tile(self):
|
||||
# tile option not allowed for 1.5.1.
|
||||
"""tile option not allowed for 1.5.1.
|
||||
"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
with self.assertRaises(TypeError) as ce:
|
||||
d = j2k.read(tile=0)
|
||||
with self.assertRaises(TypeError):
|
||||
j2k.read(tile=0)
|
||||
|
||||
def test_layer(self):
|
||||
# layer option not allowed for 1.5.1.
|
||||
"""layer option not allowed for 1.5.1.
|
||||
"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
with self.assertRaises(TypeError) as ce:
|
||||
d = j2k.read(layer=1)
|
||||
with self.assertRaises(TypeError):
|
||||
j2k.read(layer=1)
|
||||
|
||||
def test_basic_jp2(self):
|
||||
# This test is only useful when openjp2 is not available
|
||||
# and OPJ_DATA_ROOT is not set. We need at least one
|
||||
# working JP2 test.
|
||||
"""This test is only useful when openjp2 is not available
|
||||
and OPJ_DATA_ROOT is not set. We need at least one
|
||||
working JP2 test.
|
||||
"""
|
||||
j2k = Jp2k(self.jp2file)
|
||||
d = j2k.read(rlevel=1)
|
||||
j2k.read(rlevel=1)
|
||||
|
||||
def test_basic_j2k(self):
|
||||
# This test is only useful when openjp2 is not available
|
||||
# and OPJ_DATA_ROOT is not set. We need at least one
|
||||
# working J2K test.
|
||||
"""This test is only useful when openjp2 is not available
|
||||
and OPJ_DATA_ROOT is not set. We need at least one
|
||||
working J2K test.
|
||||
"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
d = j2k.read()
|
||||
j2k.read()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
The tests defined here roughly correspond to what is in the OpenJPEG test
|
||||
suite.
|
||||
"""
|
||||
#pylint: disable-all
|
||||
|
||||
from contextlib import contextmanager
|
||||
import os
|
||||
|
|
@ -4215,7 +4216,8 @@ class TestSuiteDump(unittest.TestCase):
|
|||
|
||||
# Jp2 Header
|
||||
# Colour specification
|
||||
self.assertEqual(jp2.box[3].box[1].method, glymur.core.RESTRICTED_ICC_PROFILE) # enumerated
|
||||
self.assertEqual(jp2.box[3].box[1].method,
|
||||
glymur.core.RESTRICTED_ICC_PROFILE) # enumerated
|
||||
self.assertEqual(jp2.box[3].box[1].precedence, 0)
|
||||
self.assertEqual(jp2.box[3].box[1].approximation, 1) # JPX exact
|
||||
self.assertEqual(jp2.box[3].box[1].icc_profile['Size'], 546)
|
||||
|
|
@ -4312,7 +4314,8 @@ class TestSuiteDump(unittest.TestCase):
|
|||
|
||||
# Jp2 Header
|
||||
# Colour specification
|
||||
self.assertEqual(jp2.box[3].box[1].method, glymur.core.RESTRICTED_ICC_PROFILE)
|
||||
self.assertEqual(jp2.box[3].box[1].method,
|
||||
glymur.core.RESTRICTED_ICC_PROFILE)
|
||||
self.assertEqual(jp2.box[3].box[1].precedence, 0)
|
||||
self.assertEqual(jp2.box[3].box[1].approximation, 1) # JPX exact
|
||||
self.assertEqual(jp2.box[3].box[1].icc_profile['Size'], 13332)
|
||||
|
|
@ -4362,7 +4365,8 @@ class TestSuiteDump(unittest.TestCase):
|
|||
|
||||
# Jp2 Header
|
||||
# Colour specification
|
||||
self.assertEqual(jp2.box[2].box[1].method, glymur.core.RESTRICTED_ICC_PROFILE) # enumerated
|
||||
self.assertEqual(jp2.box[2].box[1].method,
|
||||
glymur.core.RESTRICTED_ICC_PROFILE) # enumerated
|
||||
self.assertEqual(jp2.box[2].box[1].precedence, 0)
|
||||
self.assertEqual(jp2.box[2].box[1].approximation, 1) # JPX exact
|
||||
self.assertEqual(jp2.box[2].box[1].icc_profile['Size'], 414)
|
||||
|
|
@ -7079,7 +7083,8 @@ class TestSuiteDump(unittest.TestCase):
|
|||
|
||||
# Jp2 Header
|
||||
# Colour specification
|
||||
self.assertEqual(jp2.box[2].box[1].method, glymur.core.RESTRICTED_ICC_PROFILE) # res icc
|
||||
self.assertEqual(jp2.box[2].box[1].method,
|
||||
glymur.core.RESTRICTED_ICC_PROFILE)
|
||||
self.assertEqual(jp2.box[2].box[1].precedence, 0)
|
||||
self.assertEqual(jp2.box[2].box[1].approximation, 0) # JP2
|
||||
self.assertIsNone(jp2.box[2].box[1].icc_profile)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
The tests here do not correspond directly to the OpenJPEG test suite, but
|
||||
seem like logical negative tests to add.
|
||||
"""
|
||||
#pylint: disable-all
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
|
@ -71,6 +72,7 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_negative_psnr_with_cratios(self):
|
||||
# Using psnr with cratios options is not allowed.
|
||||
# Not an OpenJPEG test, but close.
|
||||
|
|
@ -126,6 +128,7 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
# the end of SOT.
|
||||
self.assertEqual(c.segment[-1].marker_id, 'SOD')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_code_block_dimensions(self):
|
||||
# opj_compress doesn't allow the dimensions of a codeblock
|
||||
# to be too small or too big, so neither will we.
|
||||
|
|
@ -154,6 +157,7 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
with self.assertWarns(UserWarning) as cw:
|
||||
j = Jp2k(infile)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_precinct_size_not_multiple_of_two(self):
|
||||
# Seems like precinct sizes should be powers of two.
|
||||
ifile = Jp2k(self.j2kfile)
|
||||
|
|
@ -163,6 +167,7 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
with self.assertRaises(IOError) as ce:
|
||||
ofile.write(data, psizes=[(13, 13)])
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_codeblock_size_not_multiple_of_two(self):
|
||||
# Seems like code block sizes should be powers of two.
|
||||
ifile = Jp2k(self.j2kfile)
|
||||
|
|
@ -172,6 +177,7 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
with self.assertRaises(IOError) as ce:
|
||||
ofile.write(data, cbsize=(13, 12))
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_codeblock_size_with_precinct_size(self):
|
||||
# Seems like code block sizes should never exceed half that of
|
||||
# precinct size.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
The tests defined here roughly correspond to what is in the OpenJPEG test
|
||||
suite.
|
||||
"""
|
||||
#pylint: disable-all
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
|
@ -57,6 +58,7 @@ def read_image(infile):
|
|||
return data
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "no write support on windows, period")
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
@unittest.skipIf(no_read_backend, no_read_backend_msg)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pylint: disable-all
|
||||
import os
|
||||
import pkg_resources
|
||||
import struct
|
||||
|
|
@ -21,6 +22,7 @@ except:
|
|||
raise
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestPrintingNeedsLib(unittest.TestCase):
|
||||
|
|
@ -782,8 +784,7 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
"Problems using NamedTemporaryFile on windows.")
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_less_common_boxes(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
with open(self.jp2file, 'rb') as ifile:
|
||||
|
|
|
|||
52
release.txt
52
release.txt
|
|
@ -1,22 +1,30 @@
|
|||
| OS | Python 2.7 | Python 3.3 | Notes |
|
||||
+------------+------------+------------+----------------------------------+
|
||||
| Windows | X | | Python(xy) with OpenJPEG 1.5.1. |
|
||||
| | | | At least 25 tests should pass |
|
||||
+------------+------------+------------+----------------------------------+
|
||||
| Mac | X | | MacPorts with both OpenJPEG 1.5.1|
|
||||
| | | | and OpenJPEG svn. Maximum number|
|
||||
| | | | of tests should pass. |
|
||||
+------------+------------+------------+----------------------------------+
|
||||
| Mac | | X | MacPorts with both OpenJPEG 1.5.1|
|
||||
| | | | and OpenJPEG svn. Maximum number|
|
||||
| | | | of tests should pass. |
|
||||
+------------+------------+------------+----------------------------------+
|
||||
| Raspberry | X | | Ships with only 1.3. Should |
|
||||
| | | | error out gracefully. |
|
||||
+------------+------------+------------+----------------------------------+
|
||||
| Fedora 17 | X | | Ships with 1.4. Should error out|
|
||||
| | | | gracefully. |
|
||||
+------------+------------+------------+----------------------------------+
|
||||
| Fedora 18 | | X | Ships with 1.5.1. Some tests |
|
||||
| | | | should pass. |
|
||||
+------------+------------+------------+----------------------------------+
|
||||
| OS | Python 2.7 | Python 3.3 | Notes |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Windows | X | | Python(xy) with OpenJPEG 1.5.1. At |
|
||||
| | | | least 155 of 444 tests should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Windows | X | | Python(xy) with OpenJPEG 1.5.1 and |
|
||||
| | | | OpenJPEG svn. At least 282 of 444 |
|
||||
| | | | tests should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Mac | X | | MacPorts with both OpenJPEG 1.5.1 |
|
||||
| | | | and OpenJPEG svn. 370 of 450 tests |
|
||||
| | | | should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Mac | | X | MacPorts with both OpenJPEG 1.5.1 |
|
||||
| | | | and OpenJPEG svn. 390 of 450 |
|
||||
| | | | tests should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Fedora 19 | | X | Ships with 1.5.1. 390 of 450 tests |
|
||||
| | | | should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Fedora 18 | | X | Ships with 1.5.1. 167 of 445 tests |
|
||||
| | | | should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Fedora 17 | X | | Ships with 1.4. Should error out |
|
||||
| | | | gracefully. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
|
||||
Pylint on entire package should be at least 0.95.
|
||||
pep8 should be pass cleanly.
|
||||
Coverage should exceed 95%.
|
||||
|
|
|
|||
5
setup.py
5
setup.py
|
|
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||
import sys
|
||||
|
||||
kwargs = {'name': 'Glymur',
|
||||
'version': '0.1.10',
|
||||
'version': '0.2.2',
|
||||
'description': 'Tools for accessing JPEG2000 files',
|
||||
'long_description': open('README.md').read(),
|
||||
'author': 'John Evans',
|
||||
|
|
@ -26,9 +26,10 @@ clssfrs = ["Programming Language :: Python",
|
|||
"Programming Language :: Python :: 3.3",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Operating System :: MacOS",
|
||||
"Operating System :: POSIX :: Linux",
|
||||
"Operating System :: Microsoft :: Windows :: Windows XP",
|
||||
"Intended Audience :: Science/Research",
|
||||
"Intended Audience :: Information Technology",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue